dbaXchange.com


Database Resources
- RDBMS Server
-
Database Administration
-
Performance Tuning
-
Backup and Recovery
-
Oracle Utilities

-
SQL and PLSQL
-
Network Administration
-
Client Applications
-
Miscellaneous Stuff

Oracle's technology Sites

http://technet.oracle.com

http://metalink.oracle.com

http://asktom.oracle.com/

http://www.oramag.com


Search this site or the web


Site search Web search powered by FreeFind



 

Category     : Database Resources -> Database Administration

DB Version  : Oracle 8i / Oracle 9i

OS Details    : Sun Solaris9

Reference : Oracle Metalink, Oracle technet and Oracle Magazine

Let's start off with some details on how oracle processes SQL statements. Each time an
application or a user connects to a database instance, it is ultimately assigned to a server process that resides on the database server. The server process provides the interface between the end-user application and the database. It is responsible for checking SQL statement syntax, determining how to execute the SQL statements, executing the statements, and returning the
results to the end-user application. When a SQL statement is received by the server process, a soft parse occurs. During this phase, the statement syntax is checked for correctness, it is verified that the user has the privileges to access the objects referenced in the statement, and the SQL hash value (SHV) is computed on the statement text. The SHV is a number used to easily identify the statement within the database. Next, the library cache in the SGA is searched to determine if the SHV already exists. This will occur if the same or another server process has already run the identical SQL statement. If the SHV is found, the server process retrieves the information stored in the library cache about the statement. This includes the algorithms used to access the various objects in the query known as the execution plan. After the statement has been retrieved, if bind variables were present in the statement, the literal values are substituted and the operations specified by the execution plan are performed by the server process. This is the desired sequence of events since it produces the lowest overall resource cost for executing SQL statements and produces the fastest response time.
If the SHV corresponding to the SQL statement is not found in the library cache during the soft parse, the server process must perform a hard parse on the statement. During this operation, the execution plan for the statement must be determined and the result must be stored in the library cache. This is typically a computationally expensive step and may be time-consuming for several reasons. Depending upon the complexity of the statement, hundreds or even thousands of different permutations may be tried before the optimal execution plan is discovered. By default,
the optimizer will test as many as 80,000 different execution plans to find the one with the lowest resource cost. To store the execution plan, memory must be allocated in the library cache. During this process, a number of latches must be acquired and held by the server process. Latches are simply flags or semaphores used within the database to assure that only one process at a time is writing to a specific part of a common memory object such as the library, dictionary, and buffer caches. If many sessions are concurrently performing hard parses, contention for these latches may result. This will decrease the response time for the query. If many simple unique SQL statements are executed by many sessions, the shared pool may become highly fragmented which will further exacerbate the latch contention problem. In extreme cases, latch contention may become so great that sessions are consuming more than 50% of their time waiting to acquire the latches necessary to write to the library cache. Response time and throughput for the queries will  likely become unacceptable

The following steps illustrate soft and hard parses. Note that step 5 will force all subsequent SQL statements to hard parse the next time that they are run so testing on a live production system is inadvisable.

  1. ALTER SESSION SET sql_trace=true;
  2. SELECT * FROM dual WHERE 10=10;                          -- Hard Parse
  3. SELECT /* Test */ * FROM dual WHERE 10=10;          -- Hard Parse
  4. SELECT * FROM dual WHERE 10=10;                          -- Soft Parse
  5. ALTER system FLUSH shared_pool;
  6. SELECT * FROM dual WHERE 10=10;                          -- Hard Parse

To identify the SQL statements that are receiving a lot of parse calls execute the following query:

  select sql_text, parse_calls, executions from v$sqlarea
  where parse_calls > 100 and executions < 2*parse_calls;

To identify the total amount of parsing going on in the system execute the
following:

select name, value from v$sysstat where name like 'parse count%';

    NAME                                                               VALUE
    -----------------------------------------------            ----------
    parse count (total)                                          123456
    parse count (hard)                                            12345
 

Analyzing the Raw Trace file to get parsing details (Trace output is from Oracle9i release 9.2.0 on Solaris) :

Step 1: ALTER SESSION SET sql_trace=true;
Sets up the tracing.

Step 2: select * from dual where 10=10

PARSING IN CURSOR #1 len=32 dep=0 uid=109 oct=3 lid=109 tim=328242274096 hv=2021
551448 ad='12cc8d4c'
select * from dual where 10=10
END OF STMT
PARSE #1:c=0,e=2160,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=328242274073
EXEC #1:c=0,e=126,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=328242274741
FETCH #1:c=0,e=208,p=0,cr=3,cu=0,mis=0,r=1,dep=0,og=4,tim=328242275207
FETCH #1:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=328242276279
..
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=222 op='TABLE ACCESS FULL DUAL '

From the raw trace above, the 'PARSE #1' line indicates that there has been a parse call for this statement. The 'mis=1' entry on this line indicates that this is a hard parse.

Step 3: select /* Test  */ * from dual where 10=10;

PARSING IN CURSOR #1 len=44 dep=0 uid=109 oct=3 lid=109 tim=328245863439 hv=4155
56111 ad='21cc07fc'
select /* Test */ * from dual where 10=10
END OF STMT
PARSE #1:c=10000,e=1828,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=328245863418
EXEC #1:c=0,e=77,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=328245863867
FETCH #1:c=0,e=167,p=0,cr=3,cu=0,mis=0,r=1,dep=0,og=4,tim=328245864284
FETCH #1:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=328245865330
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=222 op='TABLE ACCESS FULL DUAL '

Another 'hard' parse (mis=1) as expected since this SQL has not been parsed before.

Step 4: select * from dual where 10=10;

PARSING IN CURSOR #1 len=32 dep=0 uid=109 oct=3 lid=109 tim=328250975145 hv=2021
551448 ad='21cc5d4c'
select * from dual where 600=600
END OF STMT
PARSE #1:c=0,e=354,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=328250975125
EXEC #1:c=0,e=108,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=328250975561
FETCH #1:c=0,e=184,p=0,cr=3,cu=0,mis=0,r=1,dep=0,og=4,tim=328250976009
FETCH #1:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=328250977032
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=222 op='TABLE ACCESS FULL DUAL '

Since this select is a repeat of Step 2 it has already been parsed and, in this case, 
the parse information is still in the library cache, the query is found in the shared pool and a soft parse 
occurs. The parse line shows this as mis=0. 

Step 5: ALTER system FLUSH shared_pool;
This step 'removes' all the SQL in the shared pool

Step 6: select * from dual where 600=600;

PARSING IN CURSOR #1 len=33 dep=0 uid=109 oct=3 lid=109 tim=328261680757 hv=2409
74811 ad='21fff274'
select * from dual where 600=600
END OF STMT
PARSE #1:c=60000,e=63411,p=0,cr=57,cu=0,mis=1,r=0,dep=0,og=4,tim=328261680736
EXEC #1:c=0,e=71,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=328261681114
FETCH #1:c=0,e=138,p=0,cr=3,cu=0,mis=0,r=1,dep=0,og=4,tim=328261681504
FETCH #1:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=328261682605 XCTEND rlbk=0, 
rd_onfiltered=1
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=222 op='TABLE ACCESS FULL OBJ#(222) ' 


(The trace output above follows large amounts of recursive SQL that has also had to be reparsed due to flushing ALL SQL from the shared pool). The query in this step is the same as the query in Step 2 and Step 4 Step 2 was a hard parse whereas Step 4 was soft parsed. This time a hard parse is required since the SQL has been flushed from the shared pool and so the parse line shows 'mis=1'.

TKProf Output:

If the output is formatted in TKProf then it will look similar to the following:

Steps 2, 4 and 6:

select * from dual where 10=10
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        3      0.03       0.32          0          4          0           0
Execute    3      0.00       0.00          0          0          0           0
Fetch        6      0.00       0.00          0          9          0           3
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       12      0.03       0.32          0         13          0           3
Misses in library cache during parse: 2
Optimizer goal: CHOOSE
Parsing user id: 109
 
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL DUAL
 
Note: The Parse count above shows 3 parse calls. This consists of two Hard Parses 
(Step 2 and Step 6) and a single soft parse (Step 4). Misses in library cache during parse: 
2 records where the SQL was not found (i.e. a library cache miss) in the library cache and 
indicates that 2 of the parses were hard parses. Step 4 found an existing entry in the library 
cache for this statement and therefore, only a soft parse was necessary. 

Step 3:

select /* Test */ * from dual where 10=10
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse       1      0.00       0.00          0          0          0           0
Execute    1      0.00       0.00          0          0          0           0
Fetch        2      0.00       0.00          0          3          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0          3          0           1
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 109
 
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL DUAL

In this case the Query shows a hard parse as the parse count is 1 and the 'Misses in library cache during parse: 1'.

Querying v$sqlarea and v$sysstat dictionary views will give us an overall idea of parsing within the database since the instance startup. However, using SQL_TRACE at the session level will help us gather parsing information at a more granular level which will help in diagnosing database performance problems due to excessive parsing. A fix for this issue can be as easy as forcing the developers to use bind variables with their SQL statements.

Additional Notes (Added on 04/17/2007):

Things that can be done to reduce Hard parsing:

- Make sure bind variables are used as part of the SQL statements

- As much as you can, try and have your application adopt the parse once and execute many type of processing.

- If third party applications are being used or if you are in a situation where SQL statements cannot be changed to use bind variables, try the possibility of automatic binding by setting cursor_sharing=true. This can be set at the session level but extensive testing need to be done since changing this parameter can affect execution plans for sql statements.

- Try and use PLSQL with static SQL statements as much as possible.

- For batch or bulk processing, use bulk binding to do array DMLs which will reduce the overall number of parsing.

Things that can be done to reduce SOFT parsing:

- SOFT parsing can be made "softer" by caching session's cursors. If PLSQL code mostly uses static SQL statements, then you can make the session cache the SQL statements by setting session_cached_cursors parameter

Example: SQL> alter session set session_cached_cursors=40;