Friday, April 30, 2021

How to install the Oracle database sample schemas

1. go to https://github.com/oracle/db-sample-schemas/releases/latest and download the desired version of the sample schemas
2. Upload the zip file to your server
3. Unpack to any directory. $ORACLE_HOME/demo/schema is a good candidate
4. Prepare your file by running this perl command which replaces occurrences of the token `__SUB__CWD__` with your current directory:
perl -p -i.bak -e 's#__SUB__CWD__#'$(pwd)'#g' *.sql */*.sql */*.dat
4. Make sure you know the system and the sys password, and execute
sqlplus /nolog
@mksample systempwd syspwd hrpwd oepwd pmpwd ixpwd shpwd bipwd EXAMPLE TEMP /u01/oracle/18c/demo/schema/log/ mydb
The list of arguments is pretty obvious: 
1. system password 
2. sys password 
3-6: passwords for the sample schemas you are about to install 
7. default tablespace for the samples schemas 
8. temporary tablespace for the sample schemas 
9. log locatation 
10. connect string. When using multitenant, you need to pass a pdb name as an argument. The cdb cannot be used
 
Read more here

Solution for error when from external tables when installing the SH sample schema

If you are trying to select from the external tables created in the SH sample schemas, and receive an error like this:
SQL>select count(*) from SALES_TRANSACTIONS_EXT;
select count(*) from SALES_TRANSACTIONS_EXT
*
ERROR at line 1:
ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-04001: error opening file $ORACLE_HOME/demo/schema/log/ext_1v3.log
It is most likely because you have used the operating system variable $ORACLE_HOME during installation, like this:
sqlplus /nolog
@mksample systempwd syspwd hrpwd oepwd pmpwd ixpwd shpwd bipwd EXAMPLE TEMP $ORACLE_HOME/demo/schema/log/ mydb

This causes the directories created as a part of the installation to contain the variable rather than the physical path, and that will cause the directories to be non-working:
CREATE OR REPLACE DIRECTORY 
DATA_FILE_DIR AS '$ORACLE_HOME/demo/schema/sales_history';

CREATE OR REPLACE DIRECTORY 
LOG_FILE_DIR AS '$ORACLE_HOME/demo/schema/log';

Use an absolute path instead:
sqlplus /nolog
@mksample systempwd syspwd hrpwd oepwd pmpwd ixpwd shpwd bipwd EXAMPLE TEMP /u01/oracle/18c/demo/schema/log/ mydb

And your directories will be created correctly:
CREATE OR REPLACE DIRECTORY 
DATA_FILE_DIR AS '/u01/oracle/18c/demo/schema/sales_history';

CREATE OR REPLACE DIRECTORY 
LOG_FILE_DIR AS '/u01/oracle/18c/demo/schema/log';

You should now be able to select from your external table:
SQL>connect sh/shpwd@mydb
Connected.
SQL>select count(*) from SALES_TRANSACTIONS_EXT;

  COUNT(*)
----------
    916039
The Oracle 18c installation of the samples schemas is documented here.
The Oracle 18c sample schemas on github

How to instruct data pump import to load whatever it can from a corrupted source


Oracle 18c introduces a new option to the parameter DATA_OPTIONS: CONTINUE_LOAD_ON_FORMAT_ERROR.
This option will tell data pump import to skip forward to the start of the next granule if a stream format error is encountered while loading data.
In previous versions, if a format error was found, impdp would abort and already loaded rows would be rolled back.

If you find yourself in a situation where all recovery options have failed you, then you might save at least some of the source data using this parameter.

Used in a simple paramter file called impdp.par:
USERID=system
FULL=y 
DUMPFILE=mydumpfile.dmp 
DIRECTORY=DP
TABLE_EXISTS_ACTION=replace 
DATA_OPTIONS=CONTINUE_LOAD_ON_FORMAT_ERROR
Execute:
impdp parfile=impdp.par

The feature is documented in the 18c new features documentation.

See also the utilities documentation for 18c

How to create a private temporary table from Oracle 18c and onwards


The default is to throw away the data after a transaction ends with commit or rollback:
create private temporary table ora$ptt_mytemptab
on commit drop definition;

You could also let the data be visible for the entire duration of the session:
create private temporary table ora$ptt_mytemptab
on commit preserve definition;
The notation ora$ptt is derived from the parameter private_temp_table_prefix:
SQL>show parameter private_temp_table_prefix

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
private_temp_table_prefix            string      ORA$PTT_

It must be included in the create statement of the PTT. You can find information about your PTTs in the dictionary:
set lines 200
col table_name format a20
col tablespace_name format a20
col duration format a20
col num_rows format 99999999
SELECT sid, serial#, table_name, tablespace_name, duration, num_rows
FROM   user_private_temp_tables;
In my case the output is:

      SID    SERIAL# TABLE_NAME           TABLESPACE_NAME      DURATION              NUM_ROWS
---------- ---------- -------------------- -------------------- -------------------- ---------
       280      12720 ORA$PTT_MYTEMPTAB   TEMP                 SESSION                    107
The column "duration" will show whether it is preserving data for the session or the transaction.

Read more about PTTs in the Oracle 18c documentation

Monday, April 19, 2021

trcsess utility arguments

trcsess  [output=output_file_name]
         [session=session_id]
         [clientid=client_id]
         [service=service_name]
         [action=action_name]
         [module=module_name]
         [trace_files]
Documentation and examples for Oracle 19c can be found here

tkprof arguments

From Oracle Support note 29012.1
 print=integer    List only the first 'integer' SQL statements.
   insert=filename  List SQL statements and data inside INSERT statements.
   sys=no           TKPROF does not list SQL statements run as user SYS.
   record=filename  Record statements found in the trace file.
   sort=option      Set of zero or more of the following sort options:

     prscnt  number of times parse was called
     prscpu  cpu time parsing
     prsela  elapsed time parsing
     prsdsk  number of disk reads during parse
     prsqry  number of buffers for consistent read during parse
     prscu   number of buffers for current read during parse
     prsmis  number of misses in library cache during parse

     execnt  number of execute was called
     execpu  cpu time spent executing
     exeela  elapsed time executing
     exedsk  number of disk reads during execute
     exeqry  number of buffers for consistent read during execute
     execu   number of buffers for current read during execute
     exerow  number of rows processed during execute
     exemis  number of library cache misses during execute

     fchcnt  number of times fetch was called
     fchcpu  cpu time spent fetching
     fchela  elapsed time fetching
     fchdsk  number of disk reads during fetch
     fchqry  number of buffers for consistent read during fetch
     fchcu   number of buffers for current read during fetch
     fchrow  number of rows fetched

     userid  userid of user that parsed the cursor

Thursday, April 15, 2021

How to set up "RedoRoutes" in a Data Guard Broker configuration

In this example, the following members participate in my Data Guard Configuration: 

Database Name Role Open Mode Function
pksprod Primary OPEN Primary database
pks_stb Cascading Physical Standby MOUNTED Used for failover
pks_ro Active Data Guard READ ONLY WITH APPLY Used for reporting
pks_tstb Terminal Physical Standby MOUNTED Used for migration to a new geographical location

I am using the concept of a "Terminal Standby Database" to move the database from one geographical location to another.
In order for the cascading database to send its redo log stream to the terminal standby database, I had to configure the Data Guard Broker attribute "redoroutes", like this:
edit database "pksprod" set property redoroutes='(LOCAL : pks_stb, pks_ro ASYNC) (pks_stb : pks_tstb ASYNC)';
edit database "pks_stb" set property redoroutes =' (LOCAL :pksprod ASYNC, pks_ro ASYNC)(pksprod : pks_tstb ASYNC)';
which means
* When pksprod is primary, it shall send redo to pks_stb and pks_ro, while pks_stb shall send its redo to pks_tstb
* When pks_stb is primary, it shall send redo to pksprod and pks_ro, while pksprod shall send its redo to pks_tstb

When done, check the outcome like this:
DGMGRL> show database "pksprod" redoroutes
  RedoRoutes = '(LOCAL : pks_stb,pks_ro ASYNC)(pks_stb : pks_tstb ASYNC)'
DGMGRL> show database "pks_stb" redoroutes
  RedoRoutes = '(LOCAL : pksprod ASYNC, pks_ro ASYNC)(pksprod : pks_tstb ASYNC)'
The 12.2 documentation for the RedoRoutes attribute can be found here. You should familarize yourself with the how you can set up the redoroutes to suit your needs. In my case it was the only way I was able to get the DG configuration to work the way I was intending. It was setup using the 12.2 version of the Oracle database software.

Wednesday, April 14, 2021

How to change ownership of a symlink in unix

As pointed out in a post on StackExchange.com:
On a Linux system, when changing the ownership of a symbolic link using chown, by default it changes the target of the symbolic link (ie, whatever the symbolic link is pointing to).

Make a mount point directory in the root of your server, and give it the ownership you require:
su - 
cd /
mkdir -p /u09/fra/PRODDB01
chown -R oracle:dba u09
cd /u09/fra/PRODDB01/

Create a symlink that points to your desired destination:
ln -s /data1/onlinelog/TESTDB01 onlinelog
 ls -altr
total 8
drwxr-xr-x 3 oracle dba  4096 Apr 14 10:05 ..
lrwxrwxrwx 1 root   root   19 Apr 14 10:13 onlinelog -> /data1/onlinelog/TESTDB01
drwxr-xr-x 2 oracle dba  4096 Apr 14 10:13 .

Note that the symbolic link is owned by root, not user oracle, as I intended. The normal way of chaning ownership did not work:
chown oracle:dba onlinelog

However, add the -h option:
 chown -h oracle:dba onlinelog
And you will have your ownership of the symlink changed:
 ls -la
total 8
drwxr-xr-x 2 oracle dba 4096 Apr 14 10:14 .
drwxr-xr-x 3 oracle dba 4096 Apr 14 10:05 ..
lrwxrwxrwx 1 oracle dba   19 Apr 14 10:14 onlinelog -> /data1/onlinelog/TESTDB01

Tuesday, April 13, 2021

How to solve "RMAN-04014: startup failed: ORA-01261: Parameter db_recovery_file_dest destination string cannot be translated" during cloning

During an attempt to clone for active database I had created pfile with my desired value for the parameter db_recovery_file_dest, which was /fradata. Excerpt from init.ora used to start the instance (nomount):
cat initproddb01.ora |grep db_recovery_file_dest

*.db_recovery_file_dest='/fradata'
This directory exists on my auxilliary server and is indeed writable by the oracle software installation owner (for most installation, this user is called "oracle") After having started the instance, and executed the clone script:
DUPLICATE TARGET DATABASE
FOR STANDBY
FROM ACTIVE DATABASE
DORECOVER
SPFILE
SET DB_UNIQUE_NAME='STBY01' COMMENT 'Stanby db 1'
USING COMPRESSED BACKUPSET
NOFILENAMECHECK;
This message appears:
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of Duplicate Db command at 04/13/2021 08:07:31
RMAN-05501: aborting duplication of target database
RMAN-03015: error occurred in stored script Memory Script
RMAN-04014: startup failed: ORA-01261: Parameter db_recovery_file_dest destination string cannot be translated
ORA-01262: Stat failed on a file destination directory
Linux-x86_64 Error: 2: No such file or directory
Cause: The spfile that is created contains the target's db_recovery_file_dest setting, not the auxiliary's:
strings spfileproddb01.ora | grep db_recovery_file_dest
*.db_recovery_file_dest='/FRA' <--- this is inherited from the target database, and doesn't exist on the auxiliary server
Solution: Add a new spfile directive to your clone script:
SET DB_RECOVERY_FILE_DEST='/fradata'
and rerun.