Troubleshooting: High Version Count Issues (文档 ID 296377.1)
In this Document
|Ask Questions, Get Help, And Share Your Experiences With This Article|
|What is a 'High' Version Count?|
|What is shared SQL ?|
|What is 'SQL Metadata'?|
|Why should I be concerned about 'High' Versions?|
|How do I see the versions and why they are not shared ?|
|What do the reasons given in v$SQL_SHARED_CURSOR mean?|
|What further tracing is available.|
|Are there any times when a high version count is expected even though BINDS are being used?|
|Enhancement to obsolete parent cursors if Version Count exceeds a threshold|
|High Version Count with Adaptive Cursor Sharing|
|Troubleshooting Other Issues|
|Discuss High Version Count Issues|
The Troubleshooting Guide is provided to assist in debugging SQL sharing issues. When possible, diagnostic tools are included in the document to assist in troubleshooting problems. This document does not contain bugs/patches as these topics are addressed in the articles referenced at the bottom of this document.
Would you like to explore this topic further with other Oracle Customers, Oracle Employees, and Industry Experts?
Click here to join the discussion where you can ask questions, get help from others, and share your experiences with this specific article.
Discover discussions about other articles and helpful subjects by clicking here to access the main My Oracle Support Community page for Database Tuning.
There is no definitive definition of what a 'High' number
of versions for a particular cursor is, different systems may be able to
deal with different ranges of versions, However, AWR reports start
reporting versions over 20 for a particular cursor and so that is as
good an indicator of a potential problem as any.
Once you start getting into the hundreds or thousands range, then these are definitely 'High' counts and the causes should be examined and the numbers reduced so as to encourage the SQL to be shared. It is important to understand that sometimes high version counts are expected and not a result of any defect.
The first thing to remember is that all SQL is implicitly sharable.
When a SQL statement is entered, the RDBMS will create a hash value for
text of the statement and that hash value then helps the RDBMS to easily
find SQL already in the shared pool. It is not in the scope of this
article to discuss this in any great detail, so let's just assume
entering a series of text results in a hash value being created.
For instance :- 'select count(*) from emp' hashes to the value 4085390015
We now create a parent cursor for this sql and a single child. It does not matter that a SQL statement may never be shared - when it is first parsed a parent and a single child are created. The easy way to think of this is that the PARENT cursor is a representation of the hash value and the child cursor(s) represent the metadata for that SQL
Metadata is all the information which enables a statement to run.
For instance, in the example I have given EMP is owned by scott and
therefore has an OBJECT_ID which points to the EMP table owned by this
user. When the user SCOTT logged in, optimizer parameters are
initialised in that session for use by the statement, so this too is
used by the optimizer and is therefore metadata. There are other
examples of Metadata which will be mentioned further in this document.
Let's say this session logs out and back in again now. It then runs the same command again (as the same user). This time we already have the SQL in the shared pool (but we don't know this yet). What we do is hash the statement and then search for that hash value in the shared pool. If we find it, we can then search through the children to determine if any of them are usable by us (ie the metadata is the same). If it is, then we can share that SQL statement
I would still have one version of that SQL in the shared pool because the metadata enabled me to share the statement with the already existent child. The fundamentals are that the parent is not shared, it is the children which determine shareability.
Now - another user 'TEST' has it's own version of EMP. If that user was to now run the select statement above then what would happen is :-
1. The statement is hashed - it is hashed to the value 4085390015
2. The SQL will be found in the shared pool as it already exists
3. The children are scanned (at this point we have one child)
4. Because the OBJECT_ID of the EMP table owned by TEST is different the OBJECT_ID owned by scott we have a 'mismatch'
(Essentially, what happens here is that we have a linked list of children which we move through in turn, comparing the metadata of the current SQL with that of all the children. If there were 100 children then we would scan each of them (looking for a possible mismatch and moving on) until we found one we could share. If we cannot share any (ie. have exhausted the list of children) then we need to create a new child)
5. We therefore have to create a new child - we now have 1 PARENT and 2 CHILDREN.
Unnecessary non-sharing of SQL, and the resultant versions of SQL, is a primary cause of library cache contention. Contention reduces the performance of your database and, in extreme cases, can cause it to appear to 'hang'. When you have unnecessary versions of a cursor, each time that cursor is executed, the parse engine has to search through the list of versions to see which is the cursor that you want. This wastes CPU cycles that you could be using on something else.
The easiest way to get version information in a clear format is to use the script in the following article:
To find the reasons for mismatches see the following section: What do the reasons given in v$SQL_SHARED_CURSOR mean?
If you are unable to use that script then you can select the same information from the base views as illustrated in the examples below.
Lets use the example above and take a look at what SQL we can use to see this in the shared pool.
SCOTT runs select count(*) from emp
I can now run the following to see the PARENT statement and it's hash value and address
To see the CHILDREN (I expect to see 1 at this point) :-
ADDRESS KGLHDPAR U S O O S L S E B P I S T A B D L T R I I R L I O S M U T N F ---------------- ---------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0000000386BC2D08 0000000386BC2E58 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
We can see we have a single child (ADDRESS 0000000386BC2D08).
The mismatch information (U S O O S L etc) is all N because this is the first child. Now, if I log in as another user and run the same select (select count(*) from emp) and look again I will get the following output:-
ADDRESS KGLHDPAR U S O O S L S E B P I S T A B D L T R I I R L I O S M U T N F ---------------- ---------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0000000386BC2D08 0000000386BC2E58 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0000000386A91AA0 0000000386BC2E58 N N N N N N N N N N N N N Y N N N Y N N N N N N N N N N N N N
We can now see the 2nd child ( 0000000386A91AA0) and also the reasons
why it could not be shared with the first (The 'Y's denote a mismatch).
The reasons are:
(1) AUTH_CHECK_MISMATCH and
This is because the objects under my new user do not map to those of SCOTT (the current child). A mismatch occurs because I cannot access SCOTTs objects and translation fails since we have different object_ids for the objects in each of our schemas.
Below are the list of reasons as well as some worked examples (Those denoted by ** are the ones most often seen) :-
New in 11g :
New in 11.2:
There is no longer ROW_LEVEL_SEC_MISMATCH in 11.2.
The script version_rpt can also be run to produce a summary report of the v$sql_shared_cursor view with additional diagnostic information. The script can be found in:
Running the Script:
Generate reports for all cursors with more than 100 versions using SQL_ID (10g and up):
Generate reports for all cursors with more than 100 versions using HASH_VALUE:
Generate the report for cursor with sql_id cyzznbykb509s:
In 10G it is possible to use CURSORTRACE to aid the investigation of why cursors are not being shared. This event should only be used under the guidance of support and the resultant trace file is undocumented. To get the trace for a particular SQL statement you first of all need to get the hash_value (See the above select from v$sqlarea). You then set the trace on using:-
(levels 578-580 can be used for high level tracing (577=level 1, 578=level 2, 580=level 3)
This will write a trace file to user_dump_dest each time we try to reuse the cursor.
To turn off tracing use:-
Please note: Bug 5555371 exists in 10.2 (fixed in 10.2.0.4) where cursor trace cannot fully be turned off and single line entries will still be made to the trace file as a result. The w/a is to restart the instance. How invasive this BUG is depends on the executions of the cursor (and the size of the resultant trace file additions)
In 11.2 there is also cursordump:
(please ensure system , not session, is used as the level meaning changes)
This dumps some additional information such as expanding on the parameters for 'optimizer_mismatch' issues.
In later versions of the RDBMS there are also enhancements which dump more information as to the actual reason a child cursor could not share (ie the parameter differences). This information can be found in the REASON column of v$sql_shared_cursor and is in XML format. See Bug 16770590 for example.
Consider the following where cursor_sharing=SIMILAR
You will see several versions , each with no obvious reason for not being sharedExplanation:
One of the cursor sharing criteria when literal replacement is
enabled with cursor_sharing as similar is that bind value should match
initial bind value if the execution plan is going to change depending on
the value of the literal. The reason for this is we _might_ get a sub
optimal plan if we use the same cursor. This would typically happen when
depending on the value of the literal optimizer is going to chose a
different plan. Thus in this test case we have a predicate with > ,
if this was a equality we would always share the same child cursor. If
application developers are ready to live with a sub-optimal plan and
save on memory , then they need to set the parameter to force.
"The difference between SIMILAR and FORCE is that SIMILAR forces similar statements to share the SQL area without deteriorating execution plans.
Setting CURSOR_SHARING to FORCE forces similar statements to share the SQL area potentially deteriorating execution plans."
It is also possible to tell from 10046 trace (level 4/12 - BINDS) if a bind is considered to be unsafe
The flag oacfl2 in 9i and fl2 in 10g will show if a variable is unsafe.
In 10g (10.2.0.5) and 11g using the example query above this looks like:
The "fl2=0300" entry indicates that this is and Unsafe literal and the bind was generated by replacement :
The 0x200 entry being the important flag for determination of literal 'safety'.
For additional details on this topic see:
In 11gr2, an issue of Child cursors growing very long was introduced. An enhancement request was filed to address this issue Bug 10187168. When the child cursors grow beyond certain count be it 20 or 100, it obsoletes the parent cursors. In order to activate this enhancement bug set following:
1. If 126.96.36.199 and above, set the following parameters:
2. If 188.8.131.52.2, then set:
To show obsoleted cursor, run following query:
For more information, please read the following article regarding the enhancement involved:
With introduction of adaptive cursor sharing in 11g, there may be increased version count due to more child cursors. The adaptive cursor sharing is meant to adapt execution plans, depending on the selectivity of the bind variable. For more information on adaptive cursor sharing, please review following note:
Some known issues with Adaptive Cursor Sharing Overview:
A list of known issues can be found in:
For guidance troubleshooting other performance issues take a look at:
来自 “ ITPUB博客 ” ，链接：http://blog.itpub.net/17086096/viewspace-2123166/，如需转载，请注明出处，否则将追究法律责任。