Archive

Author Archive

Oracle utilities secrets

Oracle has “secret” undocumented utilities that are so powerful that they are reluctant to release the details to the general public. Oracle deliberately glosses-over these powerful utilities because they must write the documentation to the lowest common denominator, and these utilities can be extremely dangerous to Oracle professionals without the required work experience.

These utilities are often left inside an Oracle distribution for use exclusively by Oracle technical support, but expert Oracle DBA’s find them invaluable for advanced database operations. These undocumented utilities are described in the new book “Advanced Oracle Utilities: The Definitive Reference”.

A hidden Oracle utility is not a utility that is physically hidden in the Oracle software. Rather, a hidden utility is an executable or PL/SQL package that is either undocumented or where the documentation is difficult to find. For example, some PL/SQL packages are never loaded by the Oracle installer, yet their definitions remain in the operating system files.

The main directories where Oracle utilities reside are here:
$ORACLE_HOME/bin — This contains the binary executables used by the Oracle server. Most of the tools discussed in the Oracle Utilities book reside in this directory.
$ORACLE_HOME/plsql/demo — This contains a useful collection of SQL scripts related to many utilities, including the dbms_profiler utility.
$ORACLE_HOME/rdbms/admin — This contains many SQL scripts used for creating PL/SQL packages and their required environments.
$ORACLE_HOME/sqlplus/admin — This contains scripts used with autotrace and other utilities.
$ORACLE_HOME/otrace/admin — This is the administration directory for the Oracle Trace diagnostic tool.
$ORACLE_HOME/otrace/sysman — This is used by utilities such as oemctl and the Oracle Management Server (OMS).
$ORACLE_HOME/otrace/lib — This contains facility files used with the oerr utility.

Many of these undocumented utilities such as TKPROF have surfaced from the obscure and entered mainstream Oracle toolkits while others remain hidden inside the O/S.
Finding hidden Oracle utilities

The easiest way to find hidden utilities is to look for new packages within Oracle. The following query compares the packages in Oracle10g with new packages in Oracle11g, using a database link between two instances, each on a different release of Oracle:
select
object_name
from
dba_objects@oracle11g
where
owner = ‘SYS’
and
object_type = ‘PACKAGE BODY’
minus
select
object_name
from
dba_objects@oracle10g
where
owner = ‘SYS’
and
object_type = ‘PACKAGE BODY’;

This query will quickly display all package bodies owned by SYS that exist in Oracle11g but not in Oracle10g.
Finding hidden Oracle executable utilities

Discovering new binaries entails comparing two directories in the operating system and ignoring the duplicates entries. The dircmp UNIX command can be used to find only new entries within two directories:
dircmp — s
/u01/aoracle/product/9.0.3/bin
/u01/oracle/product/10.2.0/bin

Here we compare the bin directory of 9i with Oracle 10.2.
Using advanced Oracle utilities

Fortunately, these undocumented utilities are described in the new book “Advanced Oracle Utilities: The Definitive Reference”, where we see some extremely useful tools that are hidden inside Oracle:

BBED – This is the powerful Oracle block editor utility. BBED allows you to view and update the contents of Oracle data blocks. BBED should only be used by experts, or in conjunction with Oracle technical support.

Dbverify – This dbverify utility is very useful for

Oradebug – This powerful Oracle debugger has many valuable features for debugging Oracle sessions.

Orastack – This orastack memory stack utility allow you to see how RAM is being used within an Oracle session.

Again, these are just a small sample of the hidden utilities with Oracle

Categories: Burleson Article

Sequence of steps in Oracle SQL explain plan

When Codd and Date created the relational data model, the execution plan was an afterthought, largely because the SQL optimizer was always supposed to generate the best execution plan, and hence, there was not real need to understand the internal machinations of Oracle execution plans.

However, in the real world, all SQL tuning experts must be proficient in reading Oracle execution plans and understand the steps within a explain plans and the sequence that the steps are executed.  To successfully understand an explain plan you must be able to know the order that the plan steps are executed.

Reading an explain plan is important for many reasons, and Oracle SQL tuning experts reveal the explain plans to check many things:

·        Ensure that the tables will be joined in optimal order.

·        Determine the most restrictive indexes to fetch the rows.

·        Determine the best internal join method to use (e.g. nested loops, hash join).

·        Determine that the SQL is executing the steps in the optimal order.

Reading SQL execution plans has always been difficult, but there are some tricks to help determine the correct order that the explain plan steps are executed.

 

Ordering the sequence of execution plan steps

SQL execution plans are interpreted using a preorder traversal (reverse transversal) algorithm which you will see below.  Preorder traversal is a fancy way of saying:

1. That to read an execution plan, look for the innermost indented statement. That is generally the first statement executed but NOT always! (see example here where the innermost step is not the first step executed).

2. In most cases, if there are two statements at the same level, the first statement is executed first.

In other words, execution plans are read inside-out, starting with the most indented operation. Here are some general rules for reading an explain plan.

1. The first statement is the one that has the most indentation.

2. If two statements appear at the same level of indentation, the top statement is executed first.

To see how this works, take a look at this plan. Which operation is first to execute?

—————————————————————————

 

| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

—————————————————————————

|   0 | SELECT STATEMENT   |      |    10 |   650 |     7  (15)| 00:00:01 |

|*  1 |  HASH JOIN         |      |    10 |   650 |     7  (15)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| JOB  |     4 |   160 |     3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| EMP  |    10 |   250 |     3   (0)| 00:00:01 |

—————————————————————————

The answer is that the full table scan operation on the job table will execute first.  Let’s look at another example plan and read it…

ID  Par Operation

 

0      SELECT STATEMENT Optimizer=FIRST_ROWS

1    0   TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’

2    1     NESTED LOOPS

3    2       TABLE ACCESS (FULL) OF ‘DEPT’

4    2       INDEX (RANGE SCAN) OF ‘IX_EMP_01′ (NON-UNIQUE)

By reviewing this hierarchy of SQL execution steps, we see that the order of operations is 3,4, 2, 1.

Here is the graph for this execution plan:

To see how this query executes, we traverse the tree in reverse order. From the left most, deepest child, traverse the tree moving up, and to the right through each branch.

 

 

 

 

 

By reviewing this hierarchy of SQL execution steps, we see that the order of operations is 3,4, 2, 1:

 

SEQ  ID  Par Operation

0      SELECT STATEMENT Optimizer=CHOOSE

3    1    0   TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’

4    2    1     NESTED LOOPS

2    3    2       TABLE ACCESS (FULL) OF ‘DEPT’

1    4    2       INDEX (RANGE SCAN) OF ‘IX_EMP_01′ (NON-UNIQUE)

Understanding the sequence of explain plan steps is a critical skill, so let’s try some more examples:

Consider this SQL query:

select
a.empid,
a.ename,
b.dname

 

from
emp a,
dept b

where
a.deptno=b.deptno;

We get this execution plan:

Execution Plan

 

———————————————————-

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=40 Card=150000 Bytes=3300000)

1 0 HASH JOIN (Cost=40 Card=150000 Bytes=3300000)

2 1 TABLE ACCESS (FULL) OF ‘DEPT’ (Cost=2 Card=1 Bytes=10)

3 1 TABLE ACCESS (FULL) OF ‘EMP’ (Cost=37 Card=150000 Bytes=1800000)

What is the order of operations here?

Answer:  Execution plan steps are 2, 3, 1

 

Consider this query:

select
a.empid,
a.ename,
b.dname

 

from
emp a,
dept b

where
a.deptno=b.deptno;

We get this execution plan:


Execution Plan

 

———————————————————-

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=864 Card=150000 Bytes=3300000)

1 0 HASH JOIN (Cost=864 Card=150000 Bytes=3300000)

2 1 TABLE ACCESS (BY INDEX ROWID) OF ‘DEPT’ (Cost=826 Card=1 Bytes=10)

3 2 INDEX (FULL SCAN) OF ‘IX_DEPT_01′ (NON-UNIQUE) (Cost=26 Card=1)

4 1 TABLE ACCESS (FULL) OF ‘EMP’ (Cost=37 Card=150000 Bytes=1800000)

What is the order of operations here?

Answer:  Execution plans steps are 3, 2, 4, 1

 

Here is the same query, but slightly different plan:


select
a.empid,
a.ename,
b.dname

 

from
emp a,
dept b

where
a.deptno=b.deptno;

We get this execution plan:


Execution Plan

 

———————————————————-

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=39 Card=150000 Byte=3300000)

1    0   NESTED LOOPS (Cost=39 Card=150000 Bytes=3300000)

2 1 TABLE ACCESS (FULL) OF ‘DEPT’ (Cost=2 Card=1 Bytes=10)

3 1 TABLE ACCESS (FULL) OF ‘EMP’ (Cost=37 Card=150000 Bytes=1800000)

What is the order of operations here?

Answer:  Execution plans steps are 2, 3, 1

 

Let’s find the SQL execution steps for a three table join:

select
a.ename,
a.salary,
b.dname,
c.bonus_amount,
a.salary*c.bonus_amount

 

from
emp a,
dept b,
bonus c

where
a.deptno=b.deptno
and
a.empid=c.empid;

What is the order of operations here?


Execution Plan

 

———————————————————-

0      SELECT STATEMENT Optimizer=CHOOSE (Cost=168 Card=82 Bytes=3936)

1    0   TABLE ACCESS (BY INDEX ROWID) OF ‘EMP’ (Cost=2 Card=1 Bytes=12)

2    1     NESTED LOOPS (Cost=168 Card=82 Bytes=3936)

3    2       MERGE JOIN (CARTESIAN) (Cost=4 Card=82 Bytes=2952)

4    3         TABLE ACCESS (FULL) OF ‘DEPT’ (Cost=2 Card=1 Bytes=10)

5    3         BUFFER (SORT) (Cost=2 Card=82 Bytes=2132)

6    5           TABLE ACCESS (FULL) OF ‘BONUS’ (Cost=2 Card=82 Bytes=2132)

7    2       INDEX (RANGE SCAN) OF ‘IX_EMP_01′ (NON-UNIQUE) (Cost=1 Card=1)

This is a little tougher….

The execution order is 4,6,5,3,7,2,1.

Let’s diagram it!

Here we see that step 2 has two children, three and seven, and step 3 has two children, four and five.  Step 5 has a lone child, step 6.

 

Following our rules for preorder traversal, the execution plan steps start at step 4.

Final Exam!  What are the steps for this execution plan?

Execution Plan

 

———————————————————-

0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2871 Card=2 Bytes=143)

1    0   UNION-ALL

2    1     SORT (GROUP BY) (Cost=2003 Card=1 Bytes=59)

3    2       FILTER

4    3         HASH JOIN (Cost=1999 Card=1 Bytes=59)

5    4           INDEX (FAST FULL SCAN) OF ‘XIN8OPS_FLT_LEG’ (UNIQUE)

6    4           INDEX (RANGE SCAN) OF ‘XIN3BAG_TAG_FLT_LEG’ (UNIQUE)

7    1     SORT (GROUP BY) (Cost=868 Card=1 Bytes=84)

8    7       FILTER

9    8         NESTED LOOPS (Cost=864 Card=1 Bytes=84)

10    9           HASH JOIN (Cost=862 Card=1 Bytes=57)

11   10             INDEX (FAST FULL SCAN) OF ‘XIN1SCHED_FLT_LEG’ (UNIQUE)

12   10             INDEX (FAST FULL SCAN) OF ‘XIN8OPS_FLT_LEG’ (UNIQUE)

13    9           INDEX (RANGE SCAN) OF ‘XIN2BAG_TAG_FLT_LEG’ (UNIQUE)

Answer:  The order of operations is 5, 6, 4, 3, 2, 11, 12, 10, 13, 9, 8, 7, 1.

Categories: Burleson Article

Cloning Database using RMan

Overview

A powerful feature of RMAN is the ability to duplicate (clone), a database from a backup. It is possible to create a duplicate database on:

  • A remote server with the same file structure
  • A remote server with a different file structure
  • The local server with a different file structure

A duplicate database is distinct from a standby database, although both types of databases are created with the DUPLICATE command. A standby database is a copy of the primary database that you can update continually or periodically by using archived logs from the primary database. If the primary database is damaged or destroyed, then you can perform failover to the standby database and effectively transform it into the new primary database. A duplicate database, on the other hand, cannot be used in this way: it is not intended for failover scenarios and does not support the various standby recovery and failover options.

To prepare for database duplication, you must first create an auxiliary instance. For the duplication to work, you must connect RMAN to both the target (primary) database and an auxiliary instance started in NOMOUNT mode.

So long as RMAN is able to connect to the primary and duplicate instances, the RMAN client can run on any machine. However, all backups, copies of datafiles, and archived logs used for creating and recovering the duplicate database must be accessible by the server session on the duplicate host.

As part of the duplicating operation, RMAN manages the following:

  • Restores the target datafiles to the duplicate database and performs incomplete recovery by using all available backups and archived logs.
  • Shuts down and starts the auxiliary database.
  • Opens the duplicate database with the RESETLOGS option after incomplete recovery to create the online redo logs.
  • Generates a new, unique DBID for the duplicate database.

Preparing the Duplicate (Auxiliary) Instance for Duplication

Create an Oracle Password File

First we must create a password file for the duplicate instance.

export ORACLE_SID=APP2
orapwd file=orapwAPP2 password=manager entries=5 force=y

Ensure Oracle Net Connectivity to both Instances

Next add the appropriate entries into the TNSNAMES.ORA and LISTENER.ORA files in the $TNS_ADMIN directory.

LISTENER.ORA

APP1 = Target Database, APP2 = Auxiliary Database

LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = gentic)(PORT = 1521))
)
)

SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = APP1.WORLD)
(ORACLE_HOME = /opt/oracle/product/10.2.0)
(SID_NAME = APP1)
)
(SID_DESC =
(GLOBAL_DBNAME = APP2.WORLD)
(ORACLE_HOME = /opt/oracle/product/10.2.0)
(SID_NAME = APP2)
)
)

TNSNAMES.ORA

APP1 = Target Database, APP2 = Auxiliary Database

APP1.WORLD =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = gentic)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = APP1.WORLD)
)
)

APP2.WORLD =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = gentic)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = APP2.WORLD)
)
)

SQLNET.ORA

NAMES.DIRECTORY_PATH= (TNSNAMES)
NAMES.DEFAULT_DOMAIN = WORLD
NAME.DEFAULT_ZONE = WORLD
USE_DEDICATED_SERVER = ON

Now restart the Listener

lsnrctl stop
lsnrctl start

Create an Initialization Parameter File for the Auxiliary Instance

Create an INIT.ORA parameter file for the auxiliary instance, you can copy that from the target instance and then modify the parameters.

### Duplicate Database
### ———————————————–
# This is only used when you duplicate the database
# on the same host to avoid name conflicts

DB_FILE_NAME_CONVERT              = (/u01/oracle/db/APP1/,/u01/oracle/db/APP2/)
LOG_FILE_NAME_CONVERT             = (/u01/oracle/db/APP1/,/u01/oracle/db/APP2/,
/opt/oracle/db/APP1/,/opt/oracle/db/APP2/)

### Global database name is db_name.db_domain
### —————————————–

db_name                           = APP2
db_unique_name                    = APP2_GENTIC
db_domain                         = WORLD
service_names                     = APP2
instance_name                     = APP2

### Basic Configuration Parameters
### ——————————

compatible                        = 10.2.0.4
db_block_size                     = 8192
db_file_multiblock_read_count     = 32
db_files                          = 512
control_files                     = /u01/oracle/db/APP2/con/APP2_con01.con,
/opt/oracle/db/APP2/con/APP2_con02.con

### Database Buffer Cache, I/O
### ————————–
# The Parameter SGA_TARGET enables Automatic Shared Memory Management

sga_target                        = 500M
sga_max_size                      = 600M

### REDO Logging without Data Guard
### ——————————-

log_archive_format                = APP2_%s_%t_%r.arc
log_archive_max_processes         = 2
log_archive_dest                  = /u01/oracle/db/APP2/arc

### System Managed Undo
### ——————-

undo_management                   = auto
undo_retention                    = 10800
undo_tablespace                   = undo

### Traces, Dumps and Passwordfile
### ——————————

audit_file_dest                   = /u01/oracle/db/APP2/adm/admp
user_dump_dest                    = /u01/oracle/db/APP2/adm/udmp
background_dump_dest              = /u01/oracle/db/APP2/adm/bdmp
core_dump_dest                    = /u01/oracle/db/APP2/adm/cdmp
utl_file_dir                      = /u01/oracle/db/APP2/adm/utld
remote_login_passwordfile         = exclusive

Create a full Database Backup

Make sure that a full backup of the target is accessible on the duplicate host. You can use the following BASH script to backup the target database.

rman nocatalog target / <<-EOF
configure retention policy to recovery window of 3 days;
configure backup optimization on;
configure controlfile autobackup on;
configure default device type to disk;
configure device type disk parallelism 1 backup type to compressed backupset;
configure datafile backup copies for device type disk to 1;
configure maxsetsize to unlimited;
configure snapshot controlfile name to ‘/u01/backup/snapshot_controlfile’;
show all;

run {
allocate channel ch1 type Disk maxpiecesize = 1900M;
backup full database noexclude
include current controlfile
format ‘/u01/backup/datafile_%s_%p.bak’
tag ‘datafile_daily’;
}

run {
allocate channel ch1 type Disk maxpiecesize = 1900M;
backup archivelog all
delete all input
format ‘/u01/backup/archivelog_%s_%p.bak’
tag ‘archivelog_daily’;
}

run {
allocate channel ch1 type Disk maxpiecesize = 1900M;
backup format ‘/u01/backup/controlfile_%s.bak’ current controlfile;
}

crosscheck backup;
list backup of database;
report unrecoverable;
report schema;
report need backup;
report obsolete;
delete noprompt expired backup of database;
delete noprompt expired backup of controlfile;
delete noprompt expired backup of archivelog all;
delete noprompt obsolete recovery window of 3 days;
quit
EOF

Creating a Duplicate Database on the Local Host

Before beginning RMAN duplication, use SQL*Plus to connect to the auxiliary instance and start it in NOMOUNT mode. If you do not have a server-side initialization parameter file for the auxiliary instance in the default location, then you must specify the client-side initialization parameter file with the PFILE parameter on the DUPLICATE command.

Get original Filenames from TARGET

To rename the database files you can use the SET NEWNAME command. Therefore, get the original filenames from the target and modify these names in the DUPLICATE command.

ORACLE_SID=APP1
export ORACLE_SID

set feed off
set pagesize 10000
column name format a40 heading “Datafile”
column file# format 99 heading “File-ID”

select  name, file# from v$dbfile;

column member format a40 heading “Logfile”
column group# format 99 heading “Group-Nr”

select  member, group# from v$logfile;

Datafile                                  File-ID
—————————————-  ——-
/u01/oracle/db/APP1/sys/APP1_sys1.dbf           1
/u01/oracle/db/APP1/sys/APP1_undo1.dbf          2
/u01/oracle/db/APP1/sys/APP1_sysaux1.dbf        3
/u01/oracle/db/APP1/usr/APP1_users1.dbf         4

Logfile                                  Group-Nr
—————————————- ——–
/u01/oracle/db/APP1/rdo/APP1_log1A.rdo          1
/opt/oracle/db/APP1/rdo/APP1_log1B.rdo          1
/u01/oracle/db/APP1/rdo/APP1_log2A.rdo          2
/opt/oracle/db/APP1/rdo/APP1_log2B.rdo          2
/u01/oracle/db/APP1/rdo/APP1_log3A.rdo          3
/opt/oracle/db/APP1/rdo/APP1_log3B.rdo          3
/u01/oracle/db/APP1/rdo/APP1_log4A.rdo          4
/opt/oracle/db/APP1/rdo/APP1_log4B.rdo          4
/u01/oracle/db/APP1/rdo/APP1_log5A.rdo          5
/opt/oracle/db/APP1/rdo/APP1_log5B.rdo          5
/u01/oracle/db/APP1/rdo/APP1_log6A.rdo          6
/opt/oracle/db/APP1/rdo/APP1_log6B.rdo          6
/u01/oracle/db/APP1/rdo/APP1_log7A.rdo          7
/opt/oracle/db/APP1/rdo/APP1_log7B.rdo          7
/u01/oracle/db/APP1/rdo/APP1_log8A.rdo          8
/opt/oracle/db/APP1/rdo/APP1_log8B.rdo          8
/u01/oracle/db/APP1/rdo/APP1_log9A.rdo          9
/opt/oracle/db/APP1/rdo/APP1_log9B.rdo          9
/u01/oracle/db/APP1/rdo/APP1_log10A.rdo        10
/opt/oracle/db/APP1/rdo/APP1_log10B.rdo        10

Create Directories for the duplicate Database

mkdir -p /u01/oracle/db/APP2
mkdir -p /opt/oracle/db/APP2
cd /opt/oracle/db/APP2
mkdir con rdo
cd /u01/oracle/db/APP2
mkdir adm arc con rdo sys tmp usr bck
cd adm
mkdir admp bdmp cdmp udmp utld

Create Symbolic Links to Password and INIT.ORA File

Oracle must be able to locate the Password and INIT.ORA File.

cd $ORACLE_HOME/dbs
ln -s /home/oracle/config/10.2.0/orapwAPP2 orapwAPP2
ln -s /home/oracle/config/10.2.0/initAPP2.ora initAPP2.ora

Duplicate the Database

Now you are ready to duplicate the database APP1 to APP2.

ORACLE_SID=APP2
export ORACLE_SIDsqlplus sys/manager as sysdba
startup force nomount pfile=’/home/oracle/config/10.2.0/initAPP2.ora’;
exit;

rman TARGET sys/manager@APP1 AUXILIARY sys/manager@APP2

Recovery Manager: Release 10.2.0.4.0 – Production on Tue Oct 28 12:00:13 2008
Copyright (c) 1982, 2007, Oracle. All rights reserved.
connected to target database: APP1 (DBID=3191823649)
connected to auxiliary database: APP2 (not mounted)

RUN
{
SET NEWNAME FOR DATAFILE 1 TO ‘/u01/oracle/db/APP2/sys/APP2_sys1.dbf’;
SET NEWNAME FOR DATAFILE 2 TO ‘/u01/oracle/db/APP2/sys/APP2_undo1.dbf’;
SET NEWNAME FOR DATAFILE 3 TO ‘/u01/oracle/db/APP2/sys/APP2_sysaux1.dbf’;
SET NEWNAME FOR DATAFILE 4 TO ‘/u01/oracle/db/APP2/usr/APP2_users1.dbf’;
DUPLICATE TARGET DATABASE TO APP2
PFILE = /home/oracle/config/10.2.0/initAPP2.ora
NOFILENAMECHECK
LOGFILE GROUP 1 (‘/u01/oracle/db/APP2/rdo/APP2_log1A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log1B.rdo’) SIZE 10M REUSE,
GROUP 2 (‘/u01/oracle/db/APP2/rdo/APP2_log2A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log2B.rdo’) SIZE 10M REUSE,
GROUP 3 (‘/u01/oracle/db/APP2/rdo/APP2_log3A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log3B.rdo’) SIZE 10M REUSE,
GROUP 4 (‘/u01/oracle/db/APP2/rdo/APP2_log4A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log4B.rdo’) SIZE 10M REUSE,
GROUP 5 (‘/u01/oracle/db/APP2/rdo/APP2_log5A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log5B.rdo’) SIZE 10M REUSE,
GROUP 6 (‘/u01/oracle/db/APP2/rdo/APP2_log6A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log6B.rdo’) SIZE 10M REUSE,
GROUP 7 (‘/u01/oracle/db/APP2/rdo/APP2_log7A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log7B.rdo’) SIZE 10M REUSE,
GROUP 8 (‘/u01/oracle/db/APP2/rdo/APP2_log8A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log8B.rdo’) SIZE 10M REUSE,
GROUP 9 (‘/u01/oracle/db/APP2/rdo/APP2_log9A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log9B.rdo’) SIZE 10M REUSE,
GROUP 10 (‘/u01/oracle/db/APP2/rdo/APP2_log10A.rdo’,
‘/opt/oracle/db/APP2/rdo/APP2_log10B.rdo’) SIZE 10M REUSE;
}

The whole, long output is not shown here, but check, that RMAN was able to open the duplicate database with the RESETLOGS option.

…..
…..
contents of Memory Script:
{
Alter clone database open resetlogs;
}
executing Memory Scriptdatabase opened
Finished Duplicate Db at 28-OCT-08

As the final step, eliminate or uncomment the DB_FILE_NAME_CONVERT and LOG_FILE_NAME_CONVERT in the INIT.ORA file and restart the database.

initAPP2.ora

### Duplicate Database
### ———————————————–
# This is only used when you duplicate the database
# on the same host to avoid name conflicts
# DB_FILE_NAME_CONVERT =  (/u01/oracle/db/APP1/,/u01/oracle/db/APP2/)
# LOG_FILE_NAME_CONVERT = (/u01/oracle/db/APP1/,/u01/oracle/db/APP2/,
/opt/oracle/db/APP1/,/opt/oracle/db/APP2/)

sqlplus / as sysdba
shutdown immediate;
startup;

Total System Global Area 629145600 bytes
Fixed Size 1269064 bytes
Variable Size 251658936 bytes
Database Buffers 373293056 bytes
Redo Buffers 2924544 bytes
Database mounted.
Database opened.

Creating a Duplicate Database to Remote Host

This scenario is exactly the same as described for the local host. Copy the RMAN Backup files to the remote host on the same directory as on the localhost.

cd /u01/backup
scp gentic:/u01/backup/* .

The other steps are the same as described under «Creating a Duplicate Database on the Local Host».

Database Link Survival Guide

Overview

A database link is a schema object in one database that enables you to access objects on another database. The other database need not be an Oracle Database system. However, to access non-Oracle systems you must use Oracle Heterogeneous Services.

Once you have created a database link, you can use it to refer to tables and views on the other database. In SQL statements, you can refer to a table or view on the other database by appending @dblink to the table or view name. You can query a table or view on the other database with the SELECT statement. You can also access remote tables and views using any INSERT, UPDATE, DELETE, or LOCK TABLE statement.

Prerequisites

  • You must have the CREATE DATABASE LINK system privilege.
  • You must have the CREATE SESSION system privilege on the remote Oracle database.
  • You must be able to connect to the remote database.
  • Check GLOBAL_NAMES – to setup the name of the database link.

DB_NAME

The DB_NAME parameter is the SID of the database and is the name used when creating the database. It is specified within the INIT.ORA parameter file or in the CREATE DATABASE command.

select name, value from v$parameter where name = ‘db_name’;

DB_DOMAN

The DB_DOMAIN parameter is the value of the domain to which the database belongs. It can be the same as defined in the DNS – and is usually the company name. However you can set a DB_DOMAIN value which is not part of the DNS.

select name, value from v$parameter where name = ‘db_domain’;

GLOBAL_NAMES

GLOBAL_NAMES dictates how you might connect to a database. This variable is either TRUE or FALSE and if it is set to TRUE it enforces database links to have the same name as the remote database to which they are connecting. Usually GLOBAL_NAMES is set to TRUE.

select name, value from v$parameter where name = ‘global_names’;

Setting the Name of the Database Link

You can query GLOBAL_NAME on the remote database to find out how the name of the database name has to be on the local database.

CELLAR> sqlplus system/…@GENTIC

SQL> select global_name from global_name;

GENTIC.COMPANY.COM

So you have to set the database link name to GENTIC.COMPANY.COM if GLOBAL_NAMES is TRUE.

SQLNET

Setup your TNSNAMES.ORA so you can connect to the remote database.

GENTIC =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = gentic.company.com)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = GENTIC.COMPANY.COM)
)
)

CELLAR =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = cellar.company.com)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = CELLAR.COMPANY.COM)
)
)

Refer to Remote Table(s)

Suppose you want to refer to the table scott.aTable on GENTIC from CELLAR. On CELLAR the same name scott.aTable should be used – so you don’t have to change any code.

sqlplus system/….@CELLAR

SQL> CREATE DATABASE LINK GENTIC.COMPANY.COM
CONNECT TO
scott IDENTIFIED BY …..
USING ‘GENTIC‘;

Database link created.

SQL> DESC scott.aTable@GENTIC.COMPANY.COM;

Name                                      Null?    Type
—————————————– ——– ————–
LANGUAGE                                  NOT NULL VARCHAR2(2)
ACTIVE                                    NOT NULL NUMBER
TEXT                                               VARCHAR2(20)

SQL> SELECT * FROM scott.aTable@GENTIC.COMPANY.COM;

no rows selected

SQL> CREATE SYNONYM scott.aTable FOR scott.aTable@GENTIC.COMPANY.COM;

Synonym created.

SQL> SELECT * FROM scott.aTable;

no rows selected

SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘de’,1,’german’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘en’,1,’english’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘fr’,1,’french’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘it’,1,’italian’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘ru’,0,’russian’);
SQL> COMMIT;

SQL> SELECT * FROM scott.aTable;

LANGUA     ACTIVE TEXT
—— ———- ————————-
de              1 german
en              1 english
fr              1 french
it              1 italian
ru              0 russian

As you can see, accessing the remote table is fully transparent to the application. Exactly the same syntax can be used for the remote table if you create a synonym for the remote table.

Executing Remote Procedures

You can also execute remote procedures …

… here an example without synonym.

sqlplus system/….@CELLAR

SQL> DESC scott.aPackage@GENTIC.COMPANY.COM;

PROCEDURE aProcedure

Argument Name                  Type                    In/Out Default?
—————————— ———————– —— ——–
USER_ID                        NUMBER(10)              IN
A_NAME                         VARCHAR2(32)            IN
A_CONTENT                      VARCHAR2(4000)          IN
A_DEFAULT                      NUMBER(1)               IN

SQL> EXECUTE scott.aPackage.aProcedure@GENTIC.COMPANY.COM(1,'Test','Test',0);

PL/SQL procedure successfully completed.

And now the same with synonyms.

SQL> CREATE SYNONYM scott.aPackage for scott.aPackage@GENTIC.COMPANY.COM;

Synonym created.

SQL> EXECUTE scott.aPackage.aProcedure(1,’Test’,'Test’,0);

PL/SQL procedure successfully completed.

As you can see, executing remote procedures is fully transparent to the application. Exactly the same syntax can be used for the remote package if you create a synonym for the remote package.

Distributed / In-Doubt Transactions

A distributed transaction includes one or more statements that, individually or as a group, update data on two or more distinct nodes of a distributed database.

The two-phase commit mechanism ensures that all nodes either commit or perform a rollback together. What happens if the transaction fails because of a system or network error? The transaction becomes in-doubt.

Distributed transactions can become in-doubt in the following ways:

  • A server machine running Oracle software crashes.
  • A network connection between two or more Oracle databases involved in distributed processing is disconnected.
  • An unhandled software error occurs.

The RECO process automatically resolves in-doubt transactions when the machine, network, or software problem is resolved. Until RECO can resolve the transaction, the data is locked for both reads and writes. Oracle blocks reads because it cannot determine which version of the data to display for a query.

Manually Committing an In-Doubt Transaction

Suppose, the database  server GENTIC crashes during a distributed transaction.

Prepare distributed transaction

SQL> CREATE SYNONYM scott.aTable FOR scott.aTable@GENTIC.COMPANY.COM;
SQL> SELECT * from scott.aTable;
SQL> CREATE TABLE scott.bTable (count NUMBER);

Start the distributed transaction

SQL> INSERT INTO scott.bTable (count) values (1);
SQL> INSERT INTO scott.bTable (count) values (2);
SQL> INSERT INTO scott.bTable (count) values (3);
SQL> INSERT INTO scott.bTable (count) values (4);
SQL> INSERT INTO scott.bTable (count) values (5);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘de’,1,’german’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘en’,1,’english’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘fr’,1,’french’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘it’,1,’italian’);
SQL> INSERT INTO scott.aTable(language, active, text) VALUES (‘ru’,0,’russian’);
SQL> UPDATE scott.bTable SET count = 2 WHERE count = 1;

Now shutdown the distributed database

GENTIC> sqlplus / as sysdba;
shutdown abort;

Now try to COMMIT the distributed transaction

SQL> commit;

ERROR at line 1:
ORA-02054: transaction 1.37.5070 in-doubt
ORA-02068: following severe error from GENTIC
ORA-03113: end-of-file on communication channel

Now check the DBA_2PC_PENDING view for the LOCAL_TRAN_ID.

SET LINESIZE 500;
COL LOCAL_TRAN_ID FORMAT A13
COL GLOBAL_TRAN_ID FORMAT A50
COL STATE FORMAT A8
COL MIXED FORMAT A3
COL HOST FORMAT A10
COL COMMIT# FORMAT A10

SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID, STATE, MIXED, HOST, COMMIT#
FROM DBA_2PC_PENDING

/

LOCAL_TRAN_ID GLOBAL_TRAN_ID                        STATE    MIX HOST       COMMIT#
————- ————————————- ——– — ———- ———
1.37.5070 CELLAR.COMPANY.COM.a05b1b48.1.37.5070 prepared no  cellar     15508150

Now manually commit or rollback force the in-doubt transaction as user SYS

SQL> exit;

sqlplus / as sysdba

SQL> COMMIT FORCE ‘1.37.5070′;

Commit complete.

Manually remove an entry from the data dictionary

SQL> EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY(‘1.37.5070′);

PL/SQL procedure successfully completed.

More Information to Distributed Transactions can be found here

Database Link Types

When you create a database link, you must decide who will have access to it. The following sections describe how to create the basic types of links.

Following are examples of private database links

SQL Statement Result
CREATE DATABASE LINK link_name; A private link using the global database name to the remote database.The link uses the userid/password of the connected user. So if scott uses the link in a query, the link establishes a connection to the remote database as scott.
CREATE DATABASE LINK link_name
CONNECT TO user IDENTIFIED BY ...
USING 'service';
A private fixed user link to the database with service name service. The link connects to the remote database with the userid/password regardless of the connected user.
CREATE DATABASE LINK link_name
CONNECT TO CURRENT_USER USING 'service';
A private link to the database with service name service. The link uses the userid/password of the current user to log onto the remote database.

Following are examples of public database links

sdasd

SQL Statement Result
CREATE PUBLIC DATABASE LINK link_name; A public link to the remote database. The link uses the userid/password of the connected user. So if scott uses the link in a query, the link establishes a connection to the remote database as scott.
CREATE PUBLIC DATABASE LINK link_name
CONNECT TO CURRENT_USER USING 'service';
A public link to the database with service name service. The link uses the userid/password of the current user to log onto the remote database.
CREATE PUBLIC DATABASE LINK link_name
CONNECT TO user IDENTIFIED BY ....;
A public fixed user link. The link connects to the remote database with the userid/password.

 

Categories: Oracle Admin

Manually configure the Oracle 10g EM dbconsole

Overview

When you choose to create a preconfigured database during the Oracle 10g installation, you can select the Oracle Enterprise Manager (OEM) interface that you want to use to manage the database. The following options are available:

  • Database Grid Control

This option is available only if an Oracle Management Agent is installed on the system. When the Installer detects an Oracle Management Agent on the system, it allows you to choose this option and specify the Oracle Management Service that you want to use to manage the database.

If an Oracle Management Agent is not installed, you must choose to use Database Control to manage the database. However, if you install Oracle Management Agent after you install Oracle Database, you can then use Grid Control to manage this database.

  • Database Control

This option is selected by default if an Oracle Management Agent is not installed on the system. However, even if a Management Agent is installed, you can still choose to configure Database Control to manage the database.

Custom installation

If you choose the Custom installation type or the Advanced database configuration option during the installation, the Installer does not display the OEM setup screens. Instead, it runs the Database Configuration Assistant (DBCA) in interactive mode, which enables you to create a custom database.

DBCA also enables you to specify the Oracle Enterprise Manager interface that you want to use. Furthermore, you can also use DBCA after the installation to configure Database Control for a database that was not previously configured to use it.

However, if you decide to setup your own Database, you must install the Database Control manually.

Setup your own Database and manually install the Database Control

The Database Control relies on various underlying technologies to discover, monitor, and administer the Oracle Database environment.

From the Database Control, you can monitor and administer a single Oracle Database instance.

The Database Control Framework consists of the Database Control and its underlying technologies:

  • A local version of the Oracle Management Service designed to work with the local database or clustered database.
  • A local Oracle Management Repository installed in the local database and designed to store management data for the Database Control.

The following steps have to be performed.

Create your own Database

More information to setup your own Database can be found here:

Create the Database Control Repository and setup the OC4J Application Server

Make sure, that you can connect to the Repository Database (Test it with SQL*Plus). Examples for Setup Files can be found here:

Windows Linux
LISTENER.ORA listener.ora
SQLNET.ORA sqlnet.ora
TNSNAMES.ORA tnsnames.ora

Now start the Oracle EM dbconsole Build Script ($ORACLE_HOME/bin/emca for Linux and $ORACLE_HOME\Bin\emca.bat for Windows).

$ emca -repos create
$ emca -config dbcontrol db

STARTED EMCA at Fri May 14 10:43:22 MEST 2004
Enter the following information about the database
to be configured.

Listener port number: 1521
Database SID:
AKI1
Service name:
AKI1.WORLD
Email address for notification:
martin dot zahn at akadia dot ch
Email gateway for notification:
mailhost
Password for dbsnmp:
xxxxxxx
Password for sysman:
xxxxxxx
Password for sys:
xxxxxxx

———————————————————
You have specified the following settings

Database ORACLE_HOME: /opt/oracle/product/10.1.0
Enterprise Manager ORACLE_HOME: /opt/oracle/product/10.1.0

Database host name ……….: akira
Listener port number ………: 1521
Database SID ……………..: AKI1
Service name ……………..: AKI1
Email address for notification: martin dot zahn at akadia dot ch
Email gateway for notification: mailhost
———————————————————
Do you wish to continue? [yes/no]: yes
AM oracle.sysman.emcp.EMConfig updateReposVars
INFO: Updating file ../config/repository.variables …

Now wait about 10 Minutes to complete!

M oracle.sysman.emcp.EMConfig createRepository
INFO: Creating repository …
M oracle.sysman.emcp.EMConfig perform
INFO: Repository was created successfully
M oracle.sysman.emcp.util.PortQuery findUsedPorts
INFO: Searching services file for used port
AM oracle.sysman.emcp.EMConfig getProperties
………..
………..
INFO: Starting the DBConsole …
AM oracle.sysman.emcp.EMConfig perform
INFO: DBConsole is started successfully
INFO: >>>>>>>>>>> The Enterprise Manager URL is http://akira:5500/em <<<<<<<<<<<
Enterprise Manager configuration is completed successfully
FINISHED EMCA at Fri May 14 10:55:25 MEST 2004

Try to connect to the database Control

http://akira:5500/em

If you look at the installed schemas, you can now find the SYSMAN schema, which is the database Control Repository.

Troubleshooting

If you have troubles to connect, check your local configuration which can be found in $ORACLE_HOME/<hostname>_<SERVICE_NAME>. For Example our DbConsole Setup Directory looks as follows:

$ pwd
/opt/oracle/product/10.1.0/akira_AKI1/sysman/config

$ ls -l
-rw-r–r–    b64InternetCertificate.txt
-rw-r–r–    emagentlogging.properties
-rw-r–r–    emd.properties
-rw-r–r–    emomsintg.xml
-rw-r–r–    emomslogging.properties
-rw-r–r–    emoms.properties
-rw-r–r–    OUIinventories.add

The most important file is emoms.properties, where you can find all the configuration parameters.

#Fri May 14 10:54:49 CEST 2004
oracle.sysman.emSDK.svlt.ConsoleServerName=
akira_Management_Service
oracle.sysman.eml.mntr.emdRepPwd=0b878f6184e8319d
emdrep.ping.pingCommand=/bin/ping <hostname>
oracle.sysman.eml.mntr.emdRepPort=1521
oracle.sysman.eml.mntr.emdRepDBName=AKI1.WORLD
oracle.sysman.emSDK.svlt.ConsoleMode=standalone
oracle.sysman.emRep.dbConn.statementCacheSize=30
oracle.sysman.db.isqlplusUrl=
http\://akira\:5560/isqlplus/dynamic
oracle.sysman.emSDK.svlt.ConsoleServerPort=5500
oracle.sysman.eml.mntr.emdRepRAC=FALSE
oracle.sysman.emSDK.emd.rt.useMonitoringCred=true
oracle.sysman.eml.mntr.emdRepPwdEncrypted=TRUE
oracle.sysman.db.isqlplusWebDBAUrl=
http\://akira\:5560/isqlplus/dba/dynamic
oracle.sysman.emSDK.svlt.ConsoleServerHost=akira
oracle.sysman.emSDK.svlt.ConsoleServerHTTPSPort=5500
oracle.sysman.eml.mntr.emdRepServer=akira
oracle.sysman.eml.mntr.emdRepSID=AKI1
oracle.sysman.emSDK.sec.ReuseLogonPassword=true
oracle.sysman.eml.mntr.emdRepConnectDescriptor=
(DESCRIPTION\=(ADDRESS_LIST\=
(ADDRESS\=(PROTOCOL\=TCP)(HOST\=akira)(PORT\
=1521)))(CONNECT_DATA\=(SERVICE_NAME\=AKI1)))
oracle.sysman.eml.mntr.emdRepUser=SYSMAN
oracle.sysman.db.adm.conn.statementCacheSize=2
oracle.sysman.db.perf.conn.statementCacheSize=30

Automatically start and stop the DB-Console

$ emctl start dbconsole
$ emctl stop dbconsole
$ emctl status dbconsole

Oracle Enterprise Manager 10g Database
Control Release 10.1.0.2.0
Copyright (c) 1996, 2004 Oracle Corporation.
All rights reserved.

http://akira:5500/em/console/aboutApplication

Oracle Enterprise Manager 10g is running.
—————————————————
Logs are generated in directory
/opt/oracle/product/10.1.0/akira_AKI1/sysman/log

Here you can find a start/stop script for the DB-Console for Gentoo Linux.

Categories: Oracle Grid Control

How to load Data very fast using Partition Exchange

Overview

One of the great features about partitioning, and most specifically range-based partitioning, is the ability to load data quickly and easily with minimal impact on the current users using:

alter table call exchange partition data_2007 with table call_temp;

This command swaps over the definitions of the named partition and the CALL table, so that the data suddenly exists in the right place in the partitioned table. Moreover, with the inclusion of the two optional extra clauses, index definitions will be swapped and Oracle will not check whether the data actually belongs in the partition – so the exchange is very quick.

Example with no Parent Child Relation

In this example, the primary key and the partition key in the partitioned table CALL both are build on the same column «id». Therefore the primary key on CALL can be a LOCAL index and the indexes doesn’t become UNUSABLE (must not be rebuild) after the EXCHANGE.

– Create the Partition Table (Destination Table)

CREATE TABLE call (
id NUMBER(12,6),
v1    VARCHAR2(10),
data  VARCHAR2(100)
)
PARTITION BY RANGE(id) ( – Partion Key = Primary Key
PARTITION call_partition VALUES LESS THAN (MAXVALUE)
);

– Next, create the temporary Table which is used to load the Data offline

CREATE TABLE call_temp (
id    NUMBER(12,6),
v1    VARCHAR2(10),
data  VARCHAR2(100)
);

– Load 1′000′000 Rows into the offline Table

INSERT /*+ append ordered full(s1) use_nl(s2) */
INTO call_temp
SELECT
TRUNC((ROWNUM-1)/500,6),
TO_CHAR(ROWNUM),
RPAD(‘X’,100,’X')
FROM
all_tables s1,
all_tables s2
WHERE
ROWNUM <= 1000000;

– Add LOCAL Primary Key to the Partition Table as a local Index

ALTER TABLE call
ADD CONSTRAINT pk_call PRIMARY KEY(id)
USING INDEX (CREATE INDEX pk_call ON CALL(id) NOLOGGING LOCAL);

– Add Primary Key to the offline Table

ALTER TABLE call_temp
ADD CONSTRAINT pk_call_temp PRIMARY KEY(id)
USING INDEX (CREATE INDEX pk_call_temp ON call_temp(id) NOLOGGING);

– Now swap the offline Table into the Partition

ALTER TABLE CALL
EXCHANGE PARTITION call_partition WITH TABLE call_temp
INCLUDING INDEXES
WITHOUT VALIDATION;

Elapsed: 00:00:00.01

Oracle is checking that the exchange won’t cause a uniqueness problem. The query is searching the entire CALL table (excluding the partition we are exchanging) to see if there are any duplicates of the rows which we are loading. This is particularly daft, since the unique constraint is maintained through a local index, so it must include the partitioning key ID, which means there is only one legal partition in which a row can be, and we have already promised (through the without validation clause) that all the rows belong where we are putting them.

– For the next load, first truncate the CALL Table, then process the next load.

TRUNCATE TABLE call;

ALTER TABLE CALL
EXCHANGE PARTITION call_partition WITH TABLE call_temp
INCLUDING INDEXES
WITHOUT VALIDATION;

Example with Parent Child Relation

In this example, the primary key and the partition key in the partitioned table CALL are NOT the same. The primary key is build on the column «id», but the partition key is build on «created_date». Therefore the primary key on CALL must be a GLOBAL index and the indexes must be maintained using the clause UPDATE GLOBAL INDEXES in the EXCHANGE.

– Create and populate a small lookup table

CREATE TABLE lookup (
id            NUMBER(10),
description   VARCHAR2(50)
);

ALTER TABLE lookup ADD (
CONSTRAINT pk_lookup PRIMARY KEY (id)
);

INSERT INTO lookup (id, description) VALUES (1, ‘ONE’);
INSERT INTO lookup (id, description) VALUES (2, ‘TWO’);
INSERT INTO lookup (id, description) VALUES (3, ‘THREE’);
COMMIT;

– Create and populate a temporary table to load the data

CREATE TABLE call_temp (
id            NUMBER(10),
created_date  DATE,
lookup_id     NUMBER(10),
data          VARCHAR2(50)
);

– Load the temporary table

DECLARE
l_lookup_id    lookup.id%TYPE;
l_create_date  DATE;
BEGIN
FOR i IN 1 .. 1000000 LOOP
IF MOD(i, 3) = 0 THEN
l_create_date := ADD_MONTHS(SYSDATE, -24);
l_lookup_id   := 2;
ELSIF MOD(i, 2) = 0 THEN
l_create_date := ADD_MONTHS(SYSDATE, -12);
l_lookup_id   := 1;
ELSE
l_create_date := SYSDATE;
l_lookup_id   := 3;
END IF;
INSERT INTO call_temp (id, created_date, lookup_id, data)
VALUES (i, l_create_date, l_lookup_id, ‘Loaded Data for ‘ || i);
END LOOP;
COMMIT;
END;
/

– Apply Primary Key to the CALL_TEMP table.

ALTER TABLE call_temp ADD (
CONSTRAINT pk_call_temp PRIMARY KEY (id)
);

– Add Key and Foreign Key Constraint to the CALL_TEMP table.

CREATE INDEX idx_call_temp_created_date ON call_temp(created_date);
CREATE INDEX idx_call_temp_lookup_id ON call_temp(lookup_id);

ALTER TABLE call_temp ADD (
CONSTRAINT fk_call_temp_lookup_id
FOREIGN KEY (lookup_id)
REFERENCES lookup(id)
);

– Next we create a new table with the appropriate partition structure
– to act as the destination table. The destination must have the
– same constraints and indexes defined.

CREATE TABLE call (
id NUMBER(10),
created_date DATE,
lookup_id     NUMBER(10),
data          VARCHAR2(50)
)
PARTITION BY RANGE (created_date)
(PARTITION call_temp_created_date VALUES LESS THAN (MAXVALUE));

– Add Primary Key to CALL which must be GLOBAL

ALTER TABLE call ADD
CONSTRAINT pk_call PRIMARY KEY (id)
USING INDEX (CREATE INDEX pk_call ON CALL(id) GLOBAL
);

– Add Keys and Foreign Key Constraint to the CALL table
– which can be LOCAL

CREATE INDEX idx_call_created_date ON call(created_date) LOCAL;
CREATE INDEX idx_call_lookup_id ON call(lookup_id) LOCAL;

ALTER TABLE call ADD (
CONSTRAINT fk_call_lookup_id
FOREIGN KEY (lookup_id)
REFERENCES lookup(id)
);

– With this destination table in place we can start the conversion.
– We now switch the segments associated with the source table and the
– partition in the destination table using EXCHANGE PARTITION

SET TIMING ON;
ALTER TABLE call
EXCHANGE PARTITION call_temp_created_date
WITH TABLE call_temp
WITHOUT VALIDATION
UPDATE GLOBAL INDEXES;

Elapsed: 00:00:27.19

This is significantly slower than in the previous example!

The UPDATE GLOBAL INDEXES is needed because without it that would leave the global indexes associated with the partition in an UNUSABLE state. If the UPDATE GLOBAL INDEXES clause is added, the performance is reduced since the index rebuild is part of the issued DDL. The index updates are logged and it should only be used when the number of rows is low and data must stay available. For larger numbers of rows index rebuilds are more efficient and allow index reorganization.

Categories: Oracle PL-SQL

Bulk Insert

The Old Fashioned Way

A quick glance at the following Code should make one point very clear: This is straightforward code; unfortunately, it takes a lot of time to run – it is “old-fashioned” code, so let’s improve it using collections and bulk processing.

CREATE OR REPLACE PROCEDURE test_proc IS
BEGIN
FOR x IN (SELECT * FROM all_objects)
LOOP

INSERT INTO t1
(owner, object_name, subobject_name, object_id,
data_object_id, object_type, created, last_ddl_time,
timestamp, status, temporary, generated, secondary)
VALUES
(x.owner, x.object_name, x.subobject_name, x.object_id,
x.data_object_id, x.object_type, x.created,
x.last_ddl_time, x.timestamp, x.status, x.temporary,
x.generated, x.secondary);
END LOOP;
COMMIT;
END test_proc;
/

CREATE TABLE t1 AS SELECT * FROM all_objects WHERE 1 = 2;

SQL> set timing on;
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.84
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:15.03
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:12.54

Very slow – do not use it in that way!

USING Bulk Collect

Converting to collections and bulk processing can increase the volume and complexity of your code. If you need a serious boost in performance, however, that increase is well-justified.

Collections, an evolution of PL/SQL tables that allows us to manipulate many variables at once, as a unit. Collections, coupled with two new features introduced with Oracle 8i, BULK_COLLECT and FORALL, can dramatically increase the performance of data manipulation code within PL/SQL.

CREATE OR REPLACE PROCEDURE test_proc (p_array_size IN PLS_INTEGER DEFAULT 100)
IS
TYPE ARRAY IS TABLE OF all_objects%ROWTYPE;
l_data ARRAY;

CURSOR c IS SELECT * FROM all_objects;

BEGIN
OPEN c;
LOOP
FETCH c BULK COLLECT INTO l_data LIMIT p_array_size;

FORALL i IN 1..l_data.COUNT
INSERT INTO t1 VALUES l_data(i);

EXIT WHEN c%NOTFOUND;
END LOOP;
CLOSE c;
END test_proc;
/

SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.34
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.20
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.90

Eliminate CURSOR LOOP at all

You may eliminate the CURSOR Loop at all, the resulting Procedure is compacter and the performance is more or less the same.

CREATE OR REPLACE PROCEDURE test_proc
IS
TYPE TObjectTable IS TABLE OF ALL_OBJECTS%ROWTYPE;
ObjectTable$ TObjectTable;

BEGIN
SELECT * BULK COLLECT INTO ObjectTable$
FROM ALL_OBJECTS;

FORALL x in ObjectTable$.First..ObjectTable$.Last
INSERT INTO t1 VALUES ObjectTable$(x) ;

END;
/

SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.51
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.35
SQL> exec test_proc;

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.46

Categories: Oracle PL-SQL

Scripting Oracle RMAN Commands

Many DBAs have discovered how Oracle Recovery Manager (Oracle RMAN) can reliably back up, restore, and recover Oracle Database instances. Among its many features is the ability to script the commands for batch-centric, hands-off execution. This article discusses the ways to script Oracle RMAN commands in Oracle Database 11g and how to pick the right approach for your specific needs.

Why Script?

Why create a script for Oracle RMAN commands? There are two primary reasons:

1. Most Oracle RMAN activities are batch-oriented and can be automated. For instance, backing up a database is a repetitive activity and not something you would want to execute interactively.

2. Scripts provide consistency. For tasks of an ad hoc nature, such as recovering a database from a backup, automation is not strictly required. When a script is used to execute the activity, however, the action will be the same, regardless of the experience and expertise of the DBA performing the recovery.

There are two ways to script Oracle RMAN commands in Oracle Database 11g:

1. Use a command file. A command file is a text file residing in the file system.

2. Use a stored script. This script is stored in the Oracle RMAN catalog database and executed from the Oracle RMAN command prompt.

Command Files

Oracle RMAN command files are plain-text files and similar to shell scripts in UNIX or batch files in Microsoft Windows. Listing 1 shows a very simple example command file—named backup_ts_users.rman—used to back up the USERS tablespace. The file extension .rman is not necessary, but it is helpful in making the meaning of the file clear.

Code Listing 1: Command file for backing up USERS tablespace

connect target /
connect catalog rman/secretpass@rmancat

run {
allocate channel c1 type disk format ‘/orabak/%U’;
backup tablespace users;
}

You can call a command file in several ways. From the Oracle RMAN prompt, you can call the example command file as follows:

RMAN> @backup_ts_users.rman

Note that the command file is executed by the @ sign. It is important, however, to provide the full name of the command file, including the extension. (The Oracle RMAN executable does not expect or apply a default extension.)

You can also call the command file directly from the command line as

rman @backup_ts_users.rman

This approach for calling the script is highly useful in shell scripts or batch files for making backups. Also note that instead of using the @ sign to call the command file, you can use the cmdfile parameter as follows:

rman cmdfile=backup_ts_users.rman

Note that the CONNECT clauses are inside the backup_ts_users.rman command file, so there is no reason to provide the password in the command line—meaning that you can eliminate the risk of accidental exposure of the password. Had we not included the password of the catalog user rman inside the command file, we would have had to call the Oracle RMAN executable like this:

rman target=/ catalog=
rman/secretpass@rmancat

If this command were executed, someone on the server could easily get the password of the catalog user by checking the process. When the command file contains the connection information—including the password—for the catalog user, the sensitive information is not visible to anyone watching the process. Note that you should also set the permissions of the command file in such a way that nonadmin users will not be able to read it.

Passing parameters. The backup_ts_users.rman command file works well, but it’s too specific. It forces the output of the backup to one specific directory and backs up only one tablespace (USERS). If you want to back up to a different location or back up a different tablespace, you have to create a new script.

A better strategy is to make an Oracle RMAN command file parameter-driven. Rather than hard-coding specific values in the script, you can include parameters whose values are passed at runtime. Listing 2 shows a modified version of the backup_ts_users .rman command file, named backup_ts_generic.rman. Instead of actual values, the new command file includes the parameters (also known as placeholders or substitution variables) &1 and &2. With a parameter-driven command file, you can define any number of parameters in this manner and pass the values at runtime.

Code Listing 2: Parameter-driven command file

connect target /
connect catalog rman/secretpass@rmancat

run {
allocate channel c1 type disk format ‘&1/%U’;
backup tablespace &2;
}

A shell script, named backup_ts_generic.sh, calls the backup_ts_generic.rman command file with the values /tmp as the backup location (for parameter &1) and USERS as the tablespace name (for parameter &2):

$ORACLE_HOME/bin/rman <<EOF
@backup_ts_generic.rman “/tmp” USERS
EOF

You can make this shell script even more generic, so that the parameters are passed from the command line of the file system itself. For example, if you modify the second line in the backup_ts_generic.sh shell script so it reads

@backup_ts_generic.rman “/tmp” $1

you will be able to call the backup_ts_generic.rman command file, provide /tmp as the backup location, and pass the tablespace name in the command line. For instance, if you want to back up the MYTS1 tablespace, you can issue

backup_ts_generic.sh MYTS1

Logging. When you run Oracle RMAN scripts via an automated mechanism such as cron in UNIX or Scheduler in Windows, you are not physically watching the command window, so how do you know the output of the Oracle RMAN commands? The output is especially crucial when command execution results in an error and you need to examine the output. To capture the output, you can use the log parameter in the Oracle RMAN command line:

rman cmdfile=backup_ts_users.rman log=backup_ts_users.log

Now the output of the backup_ts_generic.rman command file will be recorded in a file named backup_ts_users.log instead of appearing on the screen. You can view this file later to examine the results of the Oracle RMAN run.

Stored Scripts

Although command files work pretty well in most cases, they have one huge drawback. A command file should be available on the server where the Oracle RMAN backup is to be run. Otherwise, from within the command file, you have to connect from the Oracle RMAN client to the server by using a connect string:

connect target sys/oracle123@remotedb

There are several problems with this setup. First, this modified command file needs to store the password of SYS or some other user with the SYSDBA privilege. In a security-conscious environment, that may not be acceptable. Second, the Oracle RMAN client may be not be compatible with the Oracle Database release. Finally, for performance reasons, you may very well want to run the Oracle RMAN client on the same server as the database itself. But what if you have databases on different servers? You will have to replicate a command file script to all servers. And when you modify the script, you will have to make sure it is copied to all those servers again.

The solution? With Oracle RMAN stored scripts, you can create scripts that are stored inside the Oracle RMAN catalog and not on the server itself. Listing 3 shows an example stored script called backup_ts_users. Because it is stored inside the Oracle RMAN catalog, you will need to connect to the catalog first, as shown in the listing. To execute this script, all you have to do is call it with the execute command from the Oracle RMAN prompt:

RMAN> run { execute script
backup_ts_users; }

Code Listing 3: Stored script for backing up USERS tablespace

C:\> rman
RMAN> connect target /
RMAN> connect catalog rman/secretpass@rmancat
RMAN> create script backup_ts_users
2> comment ‘Tablespace Users Backup’
3> {
4> allocate channel c1 type disk format ‘c:\temp\%U’;
5> backup tablespace users;
6> }

The backup_ts_users stored script created in Listing 3 is available only to the target database to which it is currently connected. It is a local stored script, and you can’t execute a local script created for one database in another. To execute a script in multiple databases, create a global stored script by using the keyword GLOBAL between CREATE and SCRIPT. For instance, to create the script shown in Listing 3 as a global stored script, replace

create script backup_ts_users

with

create global script backup_ts_users

Once created, this global stored script can be executed in any database connected to this catalog. If you need to modify the script, there is no need to copy it to all servers or databases; it’s automatically available for execution to all databases connecting to the catalog.

If the global stored script already exists and you want to update it, replace CREATE with REPLACE—

replace global script backup_ts_users

—and include the updated script text.

Parameterization. This backup_ts_users stored script has a very specific purpose: backing up the USERS tablespace. What if you want to back up a different tablespace? Rather than creating multiple scripts, you can create a generic stored script to back up any tablespace (as you did with the command files earlier).

Listing 4 shows how to create a parameterized stored script. In place of the tablespace name, Listing 4 uses the &1 parameter, whose value is passed at runtime. When a parameter-driven stored script is created, Oracle RMAN asks for an example value for any parameter used. When &1 is included as a parameter in line 5, Oracle RMAN asks for an example value. Enter users or any other example tablespace you may want to pass. Remember, the stored script merely asks for an example value; it does not store the value you used in the script itself.

Code Listing 4: Parameter-driven stored script

RMAN> create script backup_ts_any
2> comment ‘Any Tablespace Backup’
3> {
4> allocate channel c1 type disk format ‘c:\temp\%U’;
5> backup tablespace &1;
Enter value for 1: users
users;
6> }
7>

created script backup_ts_any

With the parameterized stored script created, pass the value of the parameter via a USING clause. For example, to back up the SYSTEM tablespace by using this backup_ts_any stored script, use the following Oracle RMAN command:

run { execute script
backup_ts_any using ‘SYSTEM’; }

Administration. Oracle RMAN provides features to help administer stored scripts.

To display the list of stored scripts, use the list script names command as follows:

RMAN> list script names;

List of Stored Scripts in Recovery Catalog
Scripts of Target Database ARUPLAP1
Script Name
Description
————
backup_ts_any
Any Tablespace Backup

backup_ts_users
Tablespace Users Backup

This command displays the names of local as well as global stored scripts.

To display the global scripts only, use the following command:

RMAN> list global script names;

RMAN> print global script
backup_ts_level1_any;

If the stored script you want to print is local, omit the keyword GLOBAL in the command.

To drop a script, such as backup_ts_level1_any, use the following command:

RMAN> delete global script
backup_ts_level1_any;

What if you want to create a stored script from a script file in the file system? You can import the file into the catalog. Here is an example:

RMAN> create script backup_ts_users
from file ‘backup_ts_users.rman’;

Conversely, you can create a file from a stored script (or export a stored script to a file). Here is an example:

RMAN> print script backup_ts_users
to file ‘backup_ts_users.rman’;

Conclusion

Oracle RMAN scripts provide capabilities not only for automation but also for consistency of execution. This article presented two ways to script RMAN commands: via OS-level command files and through scripts stored in a catalog database. Both approaches enable creation of generic scripts that use parameters whose values can be passed at execution time.

Rewriting SQL for faster performance

Because SQL is a declarative language, you can write the same query in many forms, each getting the same result but with vastly different execution plans and performance. Re-writing SQL for easier readability (and maintenance) plus faster performance is an important tuning tool.

Rewrite SQL to remove subqueries – Subqueries can be very problematic from a performance perspective.

Rewriting the SQL in PL/SQL – For certain queries rewriting SQL in PL/SQL can result in more than a 20x performance improvement.

Rewrite SQL to simplify query – Decomposing a query into multiple queries using the WITH clause (or global temporary tables) greatly aids performance.

In this example, we select all books that do not have any sales. Note that this is a non-correlated sub-query, but it could be re-written in several ways.
select
book_key
from
book
where
book_key NOT IN (select book_key from sales);

There are serious problems with subqueries that may return NULL values. It is a good idea to discourage the use of the NOT IN clause (which invokes a sub-query) and to prefer NOT EXISTS (which invokes a correlated sub-query), since the query returns no rows if any rows returned by the sub-query contain null values.
select
book_key
from
book
where
NOT EXISTS (select book_key from sales);

Subqueries can often be re-written to use a standard outer join, resulting in faster performance. As we may know, an outer join uses the plus sign (+) operator to tell the database to return all non-matching rows with NULL values. Hence we combine the outer join with a NULL test in the WHERE clause to reproduce the result set without using a sub-query.
select
b.book_key
from
book b,
sales s
where
b.book_key = s.book_key(+)
and
s.book_key IS NULL;

This execution plan will also be faster by eliminating the sub-query.
Rewriting SQL for better readability and faster response time speed

Here is an actual example of a poorly-written SQL query. It’s hard to read, and the execution plan is horrible:
SELECT ART.DEMO_MEMBER DEMO_MEMBER,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Weekly’)
AND GROUP_TYPE_CODE = ‘C’
) WEEKLY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Monthly’)
AND GROUP_TYPE_CODE = ‘C’
) MONTHLY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘90Day’)
AND GROUP_TYPE_CODE = ‘C’
) NINETYDAY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Annual’)
AND GROUP_TYPE_CODE = ‘C’
) ANNUAL_VALS,
‘C’ AS GROUP_TYPE_CODE
FROM
(SELECT DISTINCT PRD_DEMO_CHRSTC_MEMBER DEMO_MEMBER
FROM PPM_CIA_PREMIUM_VAL
WHERE CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Weekly’ ,
‘Monthly’,
‘Annual’ ,
‘90Day’)
AND GROUP_TYPE_CODE = ‘C’
GROUP BY PRD_DEMO_CHRSTC_MEMBER
) ART

UNION ALL
SELECT ART.DEMO_MEMBER DEMO_MEMBER,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Weekly’)
AND GROUP_TYPE_CODE = ‘T’
) WEEKLY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Monthly’)
AND GROUP_TYPE_CODE = ‘T’
) MONTHLY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘90Day’)
AND GROUP_TYPE_CODE = ‘T’
) NINETYDAY_VALS,
(SELECT PARAMETER_VALUE
FROM PPM_CIA_PREMIUM_VAL CIA_VAL
WHERE CIA_VAL.PRD_DEMO_CHRSTC_MEMBER = ART.DEMO_MEMBER
AND CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Annual’)
AND GROUP_TYPE_CODE = ‘T’
) ANNUAL_VALS,
‘T’ AS GROUP_TYPE_CODE
FROM
(SELECT DISTINCT PRD_DEMO_CHRSTC_MEMBER DEMO_MEMBER
FROM PPM_CIA_PREMIUM_VAL
WHERE CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Weekly’ ,
‘Monthly’,
‘Annual’ ,
‘90Day’)
AND GROUP_TYPE_CODE = ‘T’
GROUP BY PRD_DEMO_CHRSTC_MEMBER
) ART
ORDER BY GROUP_TYPE_CODE

Look like Greek? That’s not a good SQL practice, to write convoluted SQL! Let’s look at the same query, rewritten for clarity and faster performance.

The above convoluted query can be completely re-written. This SQL runs faster and more efficiently.

Rewritten query:

The above convoluted query can be completely re-written. This SQL runs faster and more efficiently.
SELECT ART.PRD_DEMO_CHRSTC_MEMBER DEMO_MEMBER,
SUM(DECODE(ART.INVOICE_TYPE_NAME,’Weekly’,ART.parameter_value)) WEEKLY_VALS,
SUM(DECODE(ART.INVOICE_TYPE_NAME,’Monthly’,ART.parameter_value)) MONTHLY_VALS,
SUM(DECODE(ART.INVOICE_TYPE_NAME,’90Day’,ART.parameter_value)) NINETYDAY_VALS,
SUM(DECODE(ART.INVOICE_TYPE_NAME,’Annual’,ART.parameter_value)) ANNUAL_VALS,
ART.GROUP_TYPE_CODE
FROM PPM_CIA_PREMIUM_VAL ART
WHERE CIA_NAME IN (‘Baseline’)
AND PRMA_MKT_MEMBER = ?
AND INVOICE_TYPE_NAME IN (‘Weekly’ ,
‘Monthly’,
‘Annual’ ,
‘90Day’)
AND GROUP_TYPE_CODE IN (‘C’,'T’)
GROUP BY ART.PRD_DEMO_CHRSTC_MEMBER,ART.GROUP_TYPE_CODE
ORDER BY ART.GROUP_TYPE_CODE, ART.PRD_DEMO_CHRSTC_MEMBER;

As we see, SQL is very flexible and an equivalent query can be written in many ways, all giving the same result, but with radically different readability and execution response time.

Categories: Burleson Article

Oracle 11g R2 new parallel query management enhancements

The database industry is clearly in the midst of massive server consolidation, an economic imperative whereby the old-fashioned one database/one server approach of the client-server days has been rendered obsolete. Today, single servers with 32 and 64 CPU’s and hundreds of gigabytes of RAM can host dozens of large Oracle databases.

While the 2nd age of mainframe computing came about to facilitate easier DBA management, there remain the impressive benefits of having a back of dozens of CPU’s to perform full scans very quickly.

When invoking Oracle parallel query, there are many perils and pitfalls:

Setting parallelism on at the table or system level influences the optimizer, and sometimes makes full-scan operations appear cheaper than they really are.

Determining the optimal degree of parallelism is tricky. The real optimal degree of parallelism depends on the physical placement of the data blocks on disk as well as the number of processors on the server (cpu_count).

To relieve these issues with parallel query, in Oracle 11g Release 2, the following new parallel query parameters are included:

The parallel_degree_policy parameter

The parallel_min_time_threshold parameter

The parallel_degree_limit parameter

The parallel_force_local parameter

Let’s take a close look at these important enhancements to Oracle parallel query in 11g Release 2.
The parallel_degree_policy parameter

The parallel_degree_policy parameter is related to the amount of table data residing in the data buffer cache. Using parallel_degree_policy allows Oracle to bypass direct path reads when Oracle determines that lots of the table data blocks already reside in the data buffer cache.

In traditional 32-bit systems (limited by on ly a few gig of RAM for the SGA), direct path reads (which bypass the SGA were always faster than reading a large table through the data buffer. However, with the advent of 64-bit servers with dozens of gigabytes for the db_cache_size, large tables are often be fully cached, negating the need to always perform direct path reads for parallel large-table full-table scans.

Guy Harrison conducted some benchmark tests of parallel_degree_policy and we see details on how parallel_degree_policy evaluates the caching of large tables:

“If PARALLEL_DEGREE_POLICY is set to AUTO then Oracle might perform buffered IO instead of direct path IO. . . The documentation says that the optimizer decides whether or not to use direct path depending on the size of the table and the buffer cache and the likelihood that some data might be in memory.”
The parallel_min_time_threshold parameter

The parallel_min_time_threshold parameter only allows parallel query to be invoked against large tables or indexes, those where the num_rows suggests that it will take more than nn seconds to scan the table. The default for parallel_min_time_threshold is 30 (seconds), but you can now adjust this threshold according to your optimal definition of what constitutes a “large table”. This parameter appears to be related to the deprecated small_table_threshold parameter.
The parallel_degree_limit parameter

The parallel_degree_limit parameter seta a limit on the maximum degree of parallelism. The default is cpu_count*2.
The parallel_force_local parameter

The parallel_force_local parameter prohibits “parallel parallelism”, a case where parallel queries on a RAC node are limited only to the local instance node.

Categories: Burleson Article