Total Pageviews

Friday, 10 February 2012

Setting The Oracle Database Listener Password


This short paper shows you how you can set a password for the Oracle listener. These passwords can be set either encrypted or unencrypted. Obviously I would not recommend setting clear text passwords. Whilst in some cases these can be made reasonably secure the problem is that a password is stored in clear text in a file. For completeness I will show both methods:
Setting an Oracle listener password in clear text
The listener password can be set in clear text as follows: (It should be noted that it is possible to set more than one listener password in this way.)
Open the $ORACLE_HOME/network/admin/listener.ora file and locate the name of your listener. For instance my listener has the default name LISTENER. I can see this in the following lines:
       
        LISTENER =
        (DESCRIPTION_LIST =
                                             
It is the line starting LISTENER= . Simply add a line to this file with the following format:
        PASSWORDS_{LISTENER_NAME}=somesecretpassword
                                             
i.e in my case if the listener is called LISTENER then:
        PASSWORDS_LISTENER=somesecretpassword                                              
                                             
You can also set multiple passwords as follows:
        PASSWORDS_LISTENER=(somesecretpassword,anothersecret)
Anyway above method is not the best way to secure your listener.
Setting an encrypted Oracle listener password
 It should be done with an encrypted password as follows:
        C:\oracle\ora90\network\admin>lsnrctl
       
        LSNRCTL for 32-bit Windows: Version 9.2.0.1.0 - Production on 24-FEB-2004 11:27:
        55
       
        Copyright (c) 1991, 2002, Oracle Corporation.  All rights reserved.
       
        Welcome to LSNRCTL, type "help" for information.
       
        LSNRCTL> set current_listener listener
        Current Listener is listener
 LSNRCTL> set password
        Password:
        The command completed successfully
        LSNRCTL> save_config
        Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC0)))
        Saved LISTENER configuration parameters.
        Listener Parameter File   C:\oracle\ora90\network\admin\listener.ora
        Old Parameter File   C:\oracle\ora90\network\admin\listener.bak
        The command completed successfully
        LSNRCTL>                               

You must save the configuration after setting the password otherwise it will be lost. Also you can check what was generated by looking in the listener.ora file. This is what was generated from the above commands:
        #----ADDED BY TNSLSNR 24-FEB-2004 11:29:18---
        PASSWORDS_LISTENER = F0354118688257FB
 
Should you want to remove the listener password do the following:
        C:\oracle\ora90\network\admin>lsnrctl
       
        LSNRCTL for 32-bit Windows: Version 9.2.0.1.0 - Production on 24-FEB-2004 11:32:
        05
       
        Copyright (c) 1991, 2002, Oracle Corporation.  All rights reserved.
       
        Welcome to LSNRCTL, type "help" for information.
 
LSNRCTL> stop
        Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC0)))
        The command completed successfully
 
Edit the listener.ora file to remove the lines added above and restart the listener as follows:
        C:\oracle\ora90\network\admin>lsnrctl
       
        LSNRCTL for 32-bit Windows: Version 9.2.0.1.0 - Production on 24-FEB-2004 11:33:
        34
       
        Copyright (c) 1991, 2002, Oracle Corporation.  All rights reserved.
       
        Welcome to LSNRCTL, type "help" for information.
       
        LSNRCTL> start
        Starting tnslsnr: please wait...
       
        TNSLSNR for 32-bit Windows: Version 9.2.0.1.0 - Production
        System parameter file is C:\oracle\ora90\network\admin\listener.ora
        Log messages written to C:\oracle\ora90\network\log\listener.log
        Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC0ipc
        )))
        Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=zulia)(PORT=1521)))
       
        Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC0)))
        STATUS of the LISTENER
        ------------------------
        Alias                     LISTENER
        Version                   TNSLSNR for 32-bit Windows: Version 9.2.0.1.0 - Produc
        tion
        Start Date                24-FEB-2004 11:33:38
        Uptime                    0 days 0 hr. 0 min. 2 sec
        Trace Level               off
        Security                  OFF
        SNMP                      OFF
        Listener Parameter File   C:\oracle\ora90\network\admin\listener.ora
        Listener Log File         C:\oracle\ora90\network\log\listener.log
        Listening Endpoints Summary...
          (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC0ipc)))
          (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=zulia)(PORT=1521)))
        Services Summary...
        Service "PLSExtProc" has 1 instance(s).
          Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
        Service "sans" has 1 instance(s).
          Instance "sans", status UNKNOWN, has 1 handler(s) for this service...
        The command completed successfully
 
That's it!, you should always protect your listener with a password. This is a basic security requirement. If the listener is not password protected then it can be shutdown remotely or have its configuration change or could be used to hack your server
 
 

Alert Log & Automatic Diagnostic Repository (ADR)

The alert log store information about block corruption errors, internal errors,  and the nondefault initialization
 parameters used at instance start-up. The alert log also records information about database start-up, shutdown, 
archiving, recovery, tablespace modifications, rollback segment modifications, and the data file modifications,
Create, alter and drop SQL statements on databases.
 
 Oracle 11g stores the alert log in two formats, both in the ADR. The Oracle 10g text format is still used. Additionally a second copy of the alert log is maintained formatted with XML tags. The XML tags make it easier for tools to process the alert log more efficiently and gather more detailed information. The XML based alert log is stored in the ADR directory called alert.The text copy of the alert log is in the ADR directory called cdump.

You can access the XML alert log with the XML tags stripped out of it using a tool called the ADR Command Interpreter (adrci).  This command-line utility provides quite a bit of functionality including providing the ability to strip out the XML tags from the alert log.Another feature of adrci is the ability to view the alert log using the tail option, as shown in the following example.

u01/oracle/product/db11g/db_01/bin>adrci
Copyright (c) 1982, 2006, Oracle.  All rights reserved.

ADR base = "u01/oracle/product"
 
adrci>>show alert -tail
ADR Home = u01/oracle/product/diag/rdbms/db11g/db11g:
***********************************************************************
2007-11-02 00:42:47.398000 -06:00
Logminer Bld: Lockdown Complete.  DB_TXN_SCN is
UnwindToSCN (LockdownSCN) is 1832443
2007-11-02 00:42:48.929000 -06:00
db_recovery_file_dest_size of 2048 MB is 83.44% used. This is a
user-specified limit on the amount of space that will be used by this
database for recovery-related files, and does not reflect the amount of
space available in the underlying filesystem or ASM diskgroup.
2007-11-02 00:43:45.586000 -06:00
SYS_AUTO_SQL_TUNING_TASK created SQL Profile named
"SYS_SQLPROF_0144bacb369c0000" for sql_id g0jvz8csyrtcf
during execution "EXEC_1_7".
2007-11-02 00:45:20.916000 -06:00
SYS_AUTO_SQL_TUNING_TASK created SQL Profile named "SYS_SQLPROF_0144bacb94b60001"
for sql_id d89c1mh5pvbkz during execution "EXEC_1_7".
2007-11-02 00:55:09.970000 -06:00 

The Oracle 11g change to the way the alert logs are stored and managed within ADR may pose some interesting problems for the uninitiated. This is because there are numerous ADR_HOMES that potentially could be used. Consider a case where there are two Oracle SIDs on the host running from the same Oracle Home. Each database will be creating it's own alert log. Since the databases are on the same Oracle Home, you will need to call the adrci command from the same $ORACLE_HOME/bin. When we try to issue the show alert command we run into a problem as seen in this example:
adrci> show alert -tail
DIA-48449: Tail alert can only apply to single ADR home
This error occurs because we have multiple ADR homes (because we have multiple databases) and adrci isn't sure which one it needs to be looking at. We fix this by first figuring out which ADR homes are available to us by using the show homes command. Then we define the appropriate homepath using the ADRCI command set homepath.
In this example we first find the available homes:
adrci> show homes
ADR Homes:
diag/rdbms/MYDB2/MYDB2
diag/rdbms/MYDB1/MYDB1
diag/asm/+asm/+ASM11
diag/tnslsnr/duke2/listener
Note here the homes ADRCI can access. To see the alert log of the SID MYDB2, you will point ADRCI to that home:
adrci> set homepath diag/rdbms/MYDB2/MYDB2
Now, when you issue show alert, the alert log of the MYDB2 instance is shown.
We can verify the current ADR home by issuing the show homes command again as seen here:
adrci> show homes
ADR Homes:
diag/rdbms/MYDB2/MYDB2
You can change the home at any time by issuing the set homepath command.
To make all this easier, you can save typing the set homepath command every time by creating an ADRCI script. This is a small text file with contents as shown in the following example:
set homepath diag/rdbms/MYDB2/MYDB2
show alert -tail –f
You save the file and name it something like showmydb2alert.cmd. Having created the script, you can call the script from the adrci command line.
$ adrci –script=adrci.cmd
When called in this manner, adrci will execute the commands inside the file automatically.
The listener log is also in XML in Oracle 11g. Just like the alert log then, you will not find a file called listener.log under $OH/network/log. You will find the listener log file in the ADR location $ORACLE_BASE/diag/tnslsnr/duke2/listener/alert/log.xml. Using the adrci utility we can look at that log file too:
adrci> set homepath diag/tnslsnr/duke2/listener
adrci > show alert –tail -f
 

11g New Features - Incident packaging using "adrci" utility

 

As an Oracle DBA, you interface with Oracle support many a times; specially when you are faced with some critical errors such ORA-600 or ORA-7445 etc. And each time you interact with Oracle support, you have to provide quite few logs (alert log, trace files etc.) so that support can assist you in resolving the problem. At times the SR goes back and forth just to additional information - such as providing additional trace files etc. since you may have missed it earlier.

But starting 11g, your life will become a little easy thanks to a new utility called "ADRCI" - ADR Command Interpreter. Now you don't have to dig around trace files and other files to determine the files that Support would require for analysis. You can simply use "adrci" to package all the files that would be required for analysis with a few simple commands.

Apart from the packaging ability, one can use adrci to :-
a. view alert log (show alert)
b. view other trace files
c. view health check reports
Viewing alert log and trace files is easy but as I said, the best use of this utility is to package incident / problems encountered so that can the packaged file can be easily be uploaded to Oracle support when needed. You do not have to search through trace files and other files to determine the files that are required for analysis.

Here is a quick demonstration of how useful this utility can be when you have to upload files ( required to analyze a specific problem) to Oracle support :-

1. Launch adrci

$ adrci

ADRCI: Release 11.1.0.6.0 - Beta on Mon Apr 7 16:11:06 2008

Copyright (c) 1982, 2007, Oracle. All rights reserved.

ADR base = "/app/oracle"


2. Check the incidents reported in alert log

adrci> show incident

ADR Home = /app/oracle/diag/rdbms/11GLAB:
*************************************************************************
INCIDENT_ID PROBLEM_KEY CREATE_TIME
-------------------- ----------------------------------------------------------- ----------------------------------------
21746 ORA 4031 2008-04-07 16:57:11.039525 +05:30
21745 ORA 4031 2008-04-07 16:57:00.356082 +05:30
21715 ORA 4031 2008-04-07 16:57:16.796655 +05:30
21714 ORA 4031 2008-04-07 16:57:07.883365 +05:30
21713 ORA 4031 2008-04-07 16:57:00.694116 +05:30
5 rows fetched


3. Identify the specific incident for which you want to create a package so that you can upload it to Oracle support

adrci> IPS CREATE PACKAGE INCIDENT 21713
Created package 2 based on incident id 21713, correlation level typical


This creates a pacakge of the incident 21713 in "incpkg" directory; you can then add diagnostic data to the package.

4. Finally generate the package for the incident, which then can be uploaded to metalink while seeking support from Oracle.

adrci> ips generate package 3
Generated package 3 in file /app/oracle/product/11.1.0/db_1/dbs/ORA4031_20080407170431_COM_1.zip, mode complete

5. As reported above a zip file has been created with all relevant logs. Now you can upload this zip file to Oracle support and seek their help in resolving your problem.

You can also view the information generated in "incpkg" directory

$cd /app/oracle/diag/rdbms/11GLAB/incpkg/pkg_3/seq_1
$ ls -ltr
-rw-r----- 1 oracle oinstall 499 Apr 7 17:14 metadata.xml
-rw-r----- 1 oracle oinstall 21968 Apr 7 17:14 manifest_3_1.xml
-rw-r----- 1 oracle oinstall 26270 Apr 7 17:14 manifest_3_1.txt
-rw-r----- 1 oracle oinstall 20064 Apr 7 17:14 manifest_3_1.html
drwxr-xr-x 2 oracle oinstall 4096 Apr 7 17:14 export
drwxr-xr-x 2 oracle oinstall 4096 Apr 7 17:14 crs
-rw-r----- 1 oracle oinstall 62789 Apr 7 17:14 config.xml

We used to achieve the same earlier by running some scripts or collecting the logs/trace files manually. But with adrci, this task is pretty simplified; I think this is surely going to reduce the time to diagnose and resolve any problem.

 Automatic Diagnostic Repository

It is introduced in Oracle 11g.Within the ADR, different Oracle components 
(such as individual  database instances) store data in their own ADR home. 
The ADR provides  for standardization of the location for files that Oracle is 
required to  support. This standardized file structure also makes it easy for 
Oracle  to package these files so that they can be sent to Oracle as a part of 
a Service Request. Associated with the ADR is the new diagnostic_dest parameter. 
This parameter defines the root of the ADR.The diagnostic_dest parameter deprecates
the user_dump_dest,  core_dump_dest, and background_dump_dest parameters. Any 
Oracle 11g  database will ignore these parameters and will use the diagnostic_
dest  parameter. This can be an upgrade issue, because if you do not define  the 
correct diagnostic destination directory, then the default values  will be used, 
which may not be your intent. Additionally, if the  background_dump_dest parameter
is set, a warning will appear during the  startup of the database. The database 
will start using the default  diagnostic directory location. Additionally, Oracle 
will create a small  alert log entry in the background_dump_dest location with 
just a few  lines indicating that the background_dump_dest parameter is obsolete 
and  indicating the new location where Oracle will be creating the alert  log.

The diagnostic_dest parameter defaults to a setting of $ORACLE_BASE. Should $ORACLE_BASE not be set, then diagnostic_dest will default to the value of $ORACLE_HOME. The root directory of the ADR directory structure builds from $ORACLE_BASE with a directory called diag. Under the diag directory is a subdirectory that references the product type, such as rdbms. Specific to the database, under rdbms is a directory for each database, and then a directory for each individual instance. Oracle will create all of these directories for you, except the $ORACLE_BASE directory.

As an example assume $ORACLE_BASE is /u01/oracle and the database name is mydb and that the database is a two node RAC instance. The structure of the ADR directory for that instance will be /u01/oracle/diag/rdbms/mydb/mydb1, and this would be the ADR Home directory for that database instance. Each Oracle component within the ADR infrastructure (instances, ASM, networking) will have it's own ADR home. ADR supports the use of shared storage if you are using RAC or you can use individual storage on each node. Shared storage in a RAC environment provides the ability to see the aggregate diagnostic data from any node. Also a shared ADR allows for more robust recovery options for the data recovery advisor.

Under the ADR home for a given Oracle component will be a number of other directories. For the Oracle database, some of the most common directories include the following:
  • alert - This is the location of the XML-formatted alert log..
  • cdump - This is the location of the core dumps for the database.
  • trace - This contains trace files generated by the system, as well as a text copy of the alert log.
  • incident - This directory contains multiple subdirectories, one for each incident.
The figure below provides a diagram of the ADR base structure.
ADR 141.gif
 
There is a lot of Metadata to be stored with regards to ADR. Each Oracle database (and ASM instance) has a V$DIAG_INFO view that provides information on the various ADR directories and other metadata related to ADR, such as active incidents. Here is an example of a query against the V$DIAG_INFO view:
SQL> SELECT * FROM v$diag_info;

   INST_ID NAME                      VALUE
---------- ------------------------- ----------------------------------------
         1 Diag Enabled              TRUE
         1 ADR Base                  C:\ORACLE\PRODUCT
         1 ADR Home                  C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g
         1 Diag Trace                C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\trace
         1 Diag Alert                C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\alert
         1 Diag Incident             C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\incident
         1 Diag Cdump                C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\cdump
         1 Health Monitor            C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\hm
         1 Default Trace File        C:\ORACLE\PRODUCT\diag\rdbms\db11g\
                                     db11g\trace\db11g_ora_7832.trc
         1 Active Problem Count      1
         1 Active Incident Count     1
11 rows selected.


Wednesday, 8 February 2012

Undo Tablespace

Traditionally transaction undo information was stored in Rollback Segments until a commit or rollback statement was issued. Automatic undo management allows the DBA to specify how long undo information should be retained after commit, preventing “snapshot too old” errors on long running queries.

This is done by setting the UNDO_RETENTION parameter. The default is 900 seconds (5 minutes), and you can set this parameter to guarantee that Oracle keeps undo logs for extended periods of time.

Rather than having to define and manage rollback segments, you can simply define an Undo tablespace and let Oracle take care of the rest. Turning on automatic undo management is easy. All you need to do is create an undo tablespace and set UNDO_MANAGEMENT = AUTO.
With the below information gathered by SQL query, you may have a idea to prevent undo space is running out so quickly.

Undo Segments

In Undo Segments there are three types of extents, they are

Unexpired Extents – Undo data whose age is less than the undo retention period.
Expired Extents – Undo data whose age is greater than the undo retention period.
Active Extents – Undo data that is part of the active transaction.

The sequence for using extents is as follows,

1. A new extent will be allocated from the undo tablespace when the requirement arises. As undo is being written to an undo segment, if the undo reaches the end of the current extent and the next extent contains expired undo then the new undo (generated by the current transaction) will wrap into that expired extent, in preference to grabbing a free extent from the undo tablespace free extent pool.

2. If this fails because of no available free extents and we cannot autoextend the datafile, then Oracle tries to steal an expired extent from another undo segment.

3. If it still fails because there are no extents with expired status then Oracle tries to reuse an unexpired extent from the current undo segment.

4. If even that fails, Oracle tries to steal an unexpired extent from another undo segment.

5. If all the above fails, an Out-Of-Space error will be reported.

Check the overall status for undos:

select tablespace_name, status, sum(blocks) * 8192/1024/1024/1024 GB from dba_undo_extents group by tablespace_name, status;
TABLESPACE_NAME                STATUS            GB
------------------------------ --------- ----------
UNDOTBS1                       UNEXPIRED 2.29626465
UNDOTBS2                       UNEXPIRED 11.0892944
UNDOTBS1                       EXPIRED   7.20245361
UNDOTBS2                       EXPIRED   1.80932617
UNDOTBS2                       ACTIVE       .015625
Undo Blocks per Second :

SELECT MAX(undoblks/((end_time-begin_time)*3600*24))
      "UNDO_BLOCK_PER_SEC"
  FROM v$undostat;
Optimal Undo Retention:

SELECT d.undo_size/(1024*1024) "ACTUAL UNDO SIZE [MByte]",
       SUBSTR(e.value,1,25) "UNDO RETENTION [Sec]",
       ROUND((d.undo_size / (to_number(f.value) *
       g.undo_block_per_sec))) "OPTIMAL UNDO RETENTION [Sec]"
  FROM (
       SELECT SUM(a.bytes) undo_size
          FROM v$datafile a,
               v$tablespace b,
               dba_tablespaces c
         WHERE c.contents = 'UNDO'
           AND c.status = 'ONLINE'
           AND b.name = c.tablespace_name
           AND a.ts# = b.ts#
       ) d,
       v$parameter e,
       v$parameter f,
       (
       SELECT MAX(undoblks/((end_time-begin_time)*3600*24))
              undo_block_per_sec
         FROM v$undostat
       ) g
WHERE e.name = 'undo_retention'
  AND f.name = 'db_block_size';
Calculate Needed UNDO Size for given Database Activity :

SELECT d.undo_size/(1024*1024) "ACTUAL UNDO SIZE [MByte]",
       SUBSTR(e.value,1,25) "UNDO RETENTION [Sec]",
       (TO_NUMBER(e.value) * TO_NUMBER(f.value) *
       g.undo_block_per_sec) / (1024*1024)
      "NEEDED UNDO SIZE [MByte]"
  FROM (
       SELECT SUM(a.bytes) undo_size
         FROM v$datafile a,
              v$tablespace b,
              dba_tablespaces c
        WHERE c.contents = 'UNDO'
          AND c.status = 'ONLINE'
          AND b.name = c.tablespace_name
          AND a.ts# = b.ts#
       ) d,
      v$parameter e,
       v$parameter f,
       (
       SELECT MAX(undoblks/((end_time-begin_time)*3600*24))
         undo_block_per_sec
         FROM v$undostat
       ) g
 WHERE e.name = 'undo_retention'
  AND f.name = 'db_block_size';

Cursor Sharing in oracle

Before oracle8.1.6, When application sends a SQL, oracle first check the shared pool to see if there is an exact statement in the shared pool. If the exact statement is not found, then a hard parse is necessary to generate the executable form of the statement. Setting CURSOR_SHARING to EXACT allows SQL statements to share the SQL area only when their texts match exactly. This is the default behavior. Using this setting, similar statements cannot shared; only textually exact statements can be shared

Let me demonstrate CURSOR_SHARING=EXACT

SQL> select count(*),empno from emphist group by empno;

COUNT(*) EMPNO
---------- ----------
1 7369
1 7902
4194304 7934

SQL> create index idxemphist on emphist(empno);

Index created.

SQL> execute DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT', TABNAME => 'EMPHIST',ESTIMATE_PERCENT
=> 10, METHOD_OPT => 'FOR ALL COLUMNS SIZE 1',CASCADE => TRUE);

PL/SQL procedure successfully completed.

SQL> alter system flush shared_pool;

System altered.
SQL> set autotrace traceonly explain

SQL> alter session set cursor_sharing='EXACT';

Session altered.

SQL> select count(ename) from emphist where empno=7934;

COUNT(ENAME)
------------
4194304

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2297 Card=1 Bytes=11
)

1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'EMPHIST' (Cost=2297 Card=4193270
Bytes=46125970)

SQL> select count(ename) from emphist where empno=7902;

COUNT(ENAME)
------------
1
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=11)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMPHIST' (Cost=4 Card=
1 Bytes=11)

3 2 INDEX (RANGE SCAN) OF 'IDXEMPHIST' (NON-UNIQUE) (Cost=
3 Card=1)

SQL> select count(ename) from emphist where empno=7902;

COUNT(ENAME)
------------
1

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=11)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMPHIST' (Cost=4 Card=
1 Bytes=11)

3 2 INDEX (RANGE SCAN) OF 'IDXEMPHIST' (NON-UNIQUE) (Cost=
3 Card=1)

SQL> select count(ename) from emphist where empno=7369;

COUNT(ENAME)
------------
1

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=11)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMPHIST' (Cost=4 Card=
1 Bytes=11)

3 2 INDEX (RANGE SCAN) OF 'IDXEMPHIST' (NON-UNIQUE) (Cost=
3 Card=1)

SQL> select count(ename) from emphist where empno=7369;

COUNT(ENAME)
------------
1

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=11)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMPHIST' (Cost=4 Card=
1 Bytes=11)

3 2 INDEX (RANGE SCAN) OF 'IDXEMPHIST' (NON-UNIQUE) (Cost=
3 Card=1)

SQL> set autotrace off
SQL> select sql_text
from v$sql
where sql_text like 'select count(ename) from emphist where empno=%';

SQL_TEXT
--------------------------------------------------------------------------------
select count(ename) from emphist where empno=7369
select count(ename) from emphist where empno=7902
select count(ename) from emphist where empno=7934

Conclusion : Oracle does not use bind variable and every unique SQL statement, execution plan will be generated. It forced to hardparse every uniqe SQL statement and it leads to consume lot of CPU cycles. Oracle can not hardparse hundreds of SQL statement concurrently and it end up waiting for shared pool. To overcome this problem, oracle introduced FORCE paramter to use bind variable.

In oracle8.1.6, Oracle introduced new parameter FORCE. This is accomplished by transforming the statement into a new one by replacing the literals with system generated bind variables. The problem with bind variables is that the optimizer cannot predict precise selectivity.

Using cursor_sharing = force will parse the FIRST sql statement loaded into memory and will use this execution plan for the subsequent similar sql statements. This might be a problem if the FIRST statement's literals have good selectivity but those of the subsequent statements don't. In this case the statements with poor selectivity will also use the index whereas a full table scan would perform better. However, if the firstly run statement doesn't have good selectivity and a full table scan is used, the subequent similar statements will also use FTS.

Let me demonstrate CURSOR_SHARING=FORCE

SQL> select count(ename) from employee where empno=7934;

COUNT(ENAME)
------------
2097152
SQL>

The below plan is extracted from tkprof output file. Optimizer use the FTS which is right choice.

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
2097152 TABLE ACCESS FULL OBJ#(30800)

Let us run the another query and see the execution plan.

SQL> select count(ename) from employee where empno=7902;

COUNT(ENAME)
------------
1

SQL>

The below plan is extracted from tkprof output file. Optimizer again use the FTS for this subsequent query which is bad choice.

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
1 TABLE ACCESS FULL OBJ#(30800)

SQL> select sql_text from v$sql
where sql_text like 'select count(ename) from emphist where empno=%';

SQL_TEXT
--------------------------------------------------------------------------------
select count(ename) from emphist where empno=:"SYS_B_0"

SQL>

Conclusion : Oracle generate only one plan and use for all the SQL code. This would turn the hard parse into soft parse. It would require fewer resource. FORCE option is good when the query table is not skewed and all the queries require same execution plan. But in real world, this is not a good option.

To overcome this problem, In Oracle9i we can use CURSOR_SHARING=SIMILAR setting which makes the right plan based on the statistics.

Let me demonstrate CURSOR_SHARING=SIMILAR

SQL> ALTER SYSTEM FLUSH SHARED_POOL;
System altered.
SQL>

SQL> select count(ename) from employee where empno=7934;

COUNT(ENAME)
------------
2097152

Let us run the query and see the actual execution plan. Optimizer use the FTS which is right choice.

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
2097152 TABLE ACCESS FULL OBJ#(30800)


Let us run the another query and see the actual execution plan.

SQL> select count(ename) from employee where empno=7902;

COUNT(ENAME)
------------
1

SQL>

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
1 TABLE ACCESS BY INDEX ROWID OBJ#(30800)
1 INDEX RANGE SCAN OBJ#(30801) (object id 30801)


SQL> select sql_text
from v$sql
where sql_text like 'select count(ename)%';

SQL_TEXT
--------------------------------------------------------------------------------
select count(ename) from emphist where empno=:"SYS_B_0"
select count(ename) from emphist where empno=:"SYS_B_0"
SQL>

Optimizer use the Index range scan which is right choice. Optimizer makes the right choice based on the statistics.

Conclusion : Optimizer replace the literal with bind variable and check if it requires different plan for the query based on the current statistics. If so then, optimizer mark the bind variable as unsafe and store the value in the signature of the query. Next time, user submit the query with the same bind variable value, then oracle resuse the plan. Optimizer would use the same execution plan based on the statistics if user submit the same query with different literal .

SIMILAR option resolve the issues which we had in EXACT. Exact does not use bind variable. But here it is using bind variable. In FORCE option, optimizer use the same execution plan for same query with different literal. But SIMILAR option, it use the different plan for the same query with different literal values based on the current statistics.



For more information continue reading this post

I am a bit puzzled by something you have said: "If you use CURSOR_SHARING=SIMILAR, you might reduce the number of plans generated—then again, you might have exactly the same number of plans."
What are the factors that influence the number of plans generated? I thought that if CURSOR_SHARING was set to SIMILAR, the optimizer would replace all literals with :SYS_B_?—this is what we see in our database.
CURSOR_SHARING is a parameter Oracle Database uses to control whether it will "auto-bind" a SQL statement. Oracle Database can take a query of the form SELECT * FROM TABLE WHERE COL = 'literal' and replace the 'literal' with a bind value—so the predicate will become WHERE COL = :"SYS_B_0" . This permits the reuse of the generated query plan, perhaps leading to better utilization of the shared pool and a reduction of hard parses performed by the system. The CURSOR_SHARING parameter can have one of three values:

  • EXACT : This is the default setting. With this value in place, the query is not rewritten to use bind variables.
  • FORCE : This setting rewrites the query, replacing all literals with bind values and setting up a one-size-fits-all plan—a single plan for the rewritten query. I'll demonstrate what that implies in a moment.
  • SIMILAR : This setting also rewrites the query, replacing the literals with bind variables, but can set up different plans for different bind variable combinations. This last point is why CURSOR_SHARING=SIMILAR might reduce the number of plans generated. Because multiple plans may be generated, the setting of SIMILAR may or may not reduce the number of actual plans you observe in the shared pool.


Let's first look at what might happen if I execute the same set of queries with these three settings. The queries will simply be SELECT * FROM DUAL WHERE DUMMY = <something> , and I'll use 'A' and 'B' for <something> . Then I'll look in the shared pool via the V$SQL dynamic performance view and see how many cursors were set up for each query. Listing 1 sets the three CURSOR_SHARING values, runs SELECT queries, and looks at the content of the SQL_TEXT column in V$SQL to see the actual SQL used in the queries.
Code Listing 1: EXACT, FORCE, and SIMILAR for CURSOR_SHARING

SQL> alter session set cursor_sharing=exact;
Session altered.
 
SQL> select * from dual CS_EXACT where dummy = 'A';
no rows selected
 
SQL> select * from dual CS_EXACT where dummy = 'B';
no rows selected
 
SQL> alter session set cursor_sharing=force;
Session altered.
 
SQL> select * from dual CS_FORCE where dummy = 'A';
no rows selected
 
SQL> select * from dual CS_FORCE where dummy = 'B';
no rows selected
 
SQL> alter session set cursor_sharing=similar;
Session altered.
 
SQL> select * from dual CS_SIMILAR where dummy = 'A';
no rows selected
 
SQL> select * from dual CS_SIMILAR where dummy = 'B';
no rows selected
 
SQL> select sql_text
  2   from v$sql
  3   where sql_text like 'select * from dual CS% where dummy = %'
  4   order by sql_text;
 
SQL_TEXT
---------------------------------------------------------
select * from dual CS_EXACT where dummy = 'A'
select * from dual CS_EXACT where dummy = 'B'
select * from dual CS_FORCE where dummy = :"SYS_B_0"
select * from dual CS_SIMILAR where dummy = :"SYS_B_0"


As you can see in Listing 1, with CURSOR_SHARING=EXACT (the default), every unique SQL statement I submit will create a new entry in V$SQL , it will be hard-parsed, and an execution plan will be created just for it. There can be hundreds or thousands of very similar queries in the shared pool that differ only in the literals used in the SQL statement itself. This implies that the application itself is not using bind variables, and that implies that the database is forced to hard-parse virtually every query, which, in turn, not only consumes a lot of CPU cycles but also leads to decreased scalability. The database just cannot hard-parse hundreds or thousands of SQL statements concurrently—the application ends up waiting for the shared pool to become available. One of the major scalability inhibitors in the database is not using bind variables . That was the motivation behind adding CURSOR_SHARING=FORCE in Oracle8i Release 2 (8.1.6)—to help alleviate this performance and scalability inhibitor.
With CURSOR_SHARING=FORCE in place in Listing 1, the database generated only one shareable query in the shared pool—it replaced 'A' and 'B' with :"SYS_B_0" and made the cursor shareable by as many sessions as would need it. In general, just one query plan would be reused by all sessions. This would turn the hard parse into a soft parse, which would consume fewer resources and simultaneously increase the scalability of the system, by allowing for more concurrent work, because a soft parse needs to "latch" (use a certain type of lock on) the shared pool less than a hard parse.
However, looking at the example in Listing 1 might lead you to assume that the settings of FORCE and SIMILAR are the same—the results certainly seem that way right now, because both resulted in a single plan. So what is the difference between these two settings? I'll need another example to show that, but I can describe it first. When CURSOR_SHARING is set to SIMILAR , Oracle Database will replace all literals with bind variables, just as FORCE would, but the SIMILAR value does one other thing—it looks at each literal it replaces and asks, "Could different values for this bind variable lead, in turn, to different plans?" For example, if the predicate WHERE X=6 implies that I would want to use a full scan but the predicate WHERE X=5 implies that I would want to use an index range scan, the database would recognize that and set up different plans for me. In the case of different plans, you mark the bind variable as unsafe and add its value to the signature of the query, so to reuse this cursor, you must not only have the same SQL statement but also the same value for that particular bind variable.
That is why SIMILAR might reduce the number of plans you see in the shared pool but, then again, might not. In order to let you observe this and really see what is happening, I'll set up a table with some very skewed data—so skewed that when I query WHERE ID=1 , Oracle Database will want to use an index on ID , and when I query WHERE ID=99 , Oracle Database will not want to use an index. Listing 2 creates the skewed data and index and returns the execution plans for the skewed data.
Code Listing 2: Creating table, index, and plans for skewed data

SQL> create table t
  2  as
  3  select decode(rownum,1,1,99) ID,
  4         all_objects.*
  5    from all_objects
  6  /
Table created.
 
SQL> create index t_idx on t (id);
Index created.
 
SQL> begin
  2          dbms_stats.gather_table_stats
  3          ( ownname    => USER,
  4            tabname     => 'T',
  5            method_opt => 'for all indexed columns size 254',
  6            cascade      => TRUE
  7          );
  8  end;
  9  /
PL/SQL procedure successfully completed.
 
SQL> set autotrace traceonly explain
SQL> select * from t where id=1;
 
Execution Plan
----------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1 Bytes=96)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (TABLE) (Cost=2 Card=1 Bytes=96)
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (INDEX) (Cost=1 Card=1)
 
SQL> select * from t where id=99;
 
Execution Plan
---------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=197 Card=48028 Bytes=4610688)
   1    0   TABLE ACCESS (FULL) OF 'T' (TABLE) (Cost=197 Card=48028 Bytes=4610688)


Table T in Listing 2 contains a column ID , which is very much skewed—most of the values are 99, with one record containing a value of 1. After I index and gather statistics on the table (generating histograms on that indexed column, so the optimizer knows that the data is skewed), I can see that the optimizer prefers an index range scan over a full scan when ID=1 is used and vice versa for ID=99 .
Now, let's query that table with different ID= predicates, using CURSOR_SHARING=FORCE and then SIMILAR , as shown in Listing 3 (I already know what to expect with CURSOR_SHARING=EXACT —a single plan for each unique ID value supplied).
Code Listing 3: FORCE, SIMILAR, and skewed data

SQL> alter session set cursor_sharing=force;
Session altered.
SQL> select * from t CS_FORCE where id = 1;
1 row selected.
SQL> select * from t CS_FORCE where id = 50;
no rows selected
SQL> select * from t CS_FORCE where id = 99;
48029 rows selected.
SQL> select * from t CS_FORCE where id = 1;
1 row selected.
SQL> select * from t CS_FORCE where id = 50;
no rows selected
SQL> select * from t CS_FORCE where id = 99;
48029 rows selected.
                                                                                                           
SQL> alter session set cursor_sharing=similar;
Session altered.
SQL> select * from t CS_SIMILAR where id = 1;
1 row selected.
SQL> select * from t CS_SIMILAR where id = 50;
no rows selected
SQL> select * from t CS_SIMILAR where id = 99;
48029 rows selected.
SQL> select * from t CS_SIMILAR where id = 1;
1 row selected.
SQL> select * from t CS_SIMILAR where id = 50;
no rows selected
SQL> select * from t CS_SIMILAR where id = 99;
48029 rows selected.
                                                                                                           
SQL> select sql_text
  2   from v$sql
  3   where sql_text like 'select * from t CS% where id = %'
  4   order by sql_text;
                                                                                                           
SQL_TEXT
------------------------------------------------
select * from t CS_FORCE where id = :"SYS_B_0"
select * from t CS_SIMILAR where id = :"SYS_B_0"
select * from t CS_SIMILAR where id = :"SYS_B_0"
select * from t CS_SIMILAR where id = :"SYS_B_0"


As you can see in Listing 3, when CURSOR_SHARING=FORCE was true, one—and only one—plan was generated. It was, in fact, the one-size-fits-all plan, and in this case, the plan would use the index range scan (because the first query I parsed used ID=1 and the optimizer would use that bind variable value to generate the plan).
However, when CURSOR_SHARING=SIMILAR was true in Listing 3, three plans were generated, because the optimizer detected that a different value used when searching against the ID column could lead to a different plan (the statistics generated in Listing 2 gave it that information). Hence the actual bind variable value was added to the signature of that query plan and only a query with exactly the same signature could reuse the plan. That was the purpose of running each of the queries twice: to show that cursor reuse is possible. There were not six queries in V$SQL , just four. With CURSOR_SHARING=SIMILAR cursor reuse is not guaranteed, by design .
So, does that mean that for any unique set of literals, CURSOR_SHARING=SIMILAR will generate a new plan? No, I already saw that demonstrated with the DUAL table in Listing 1 when using WHERE DUMMY='A' and WHERE DUMMY='B' . It is only when the bind variable substitution is deemed unsafe that CURSOR_SHARING=SIMILAR will generate a new plan. Using the example in Listing 2, the only unsafe binding is against the ID column—if I query against that column and some other column but keep the ID column constant, I'll see cursor reuse, as shown in Listing 4.
Code Listing 4: CURSOR_SHARING=SIMILAR

SQL> alter session set cursor_sharing=similar;
Session altered.

SQL> select * from t CS_SIMILAR where id=1 and object_id=1;
no rows selected
SQL> select * from t CS_SIMILAR where id=1 and object_id=2;
no rows selected
SQL> select * from t CS_SIMILAR where id=1 and object_id=3;
no rows selected

SQL> select sql_text
  2    from v$sql
  3   where sql_text like 'select * from t CS% where id = % and object_id=%'
  4   order by sql_text;
                                                                                                           
SQL_TEXT
-------------------------------------------------------------------------
select * from t CS_SIMILAR where id = :"SYS_B_0" and object_id=:"SYS_B_1"


I varied the literals used to search against the OBJECT_ID column—but not the ID column—in Listing 4. The optimizer recognized that OBJECT_ID is safe; it would not generate different plans based on different inputs for that column, so it did not add OBJECT_ID to the signature of the cursor. Only when a different value is used against ID will a new plan be generated.
So, that shows that CURSOR_SHARING=SIMILAR might reduce the number of entries you see in the shared pool. If this application were to vary the literals used against the ID column and use hundreds or thousands of unique values, CURSOR_SHARING=SIMILAR would not have a significant impact on the shared pool utilization. On the other hand, if the application used only two values against the ID column, CURSOR_SHARING=SIMILAR could have a dramatic, positive effect on shared pool utilization.