Quantcast
Channel: Oracle
Viewing all articles
Browse latest Browse all 1814

Blog Post: Why my execution plan has not been shared – Part III

$
0
0
In the previous instalment of this series we looked at four reasons from gv$sql_shared_cursor view and explained the situations and criteria for which Oracle is forced to compile a new execution plan. We used reproducible examples to demonstrate these reasons and to make them easily understandable. In this third instalment we will decipher two supplementary reasons from the sixty four ones exposed in the gv$sql_shared_cursor which are BIND_MISMATCH and STB_OBJ_MISMATCH . BIND_MISMATCH Here’s below how Oracle defines this reason ( Y|N ) The bind metadata does not match the existing child cursor When Oracle compile a new execution plan for a parent cursor several information are stored in memory together with the underlying child cursor. This cursor metadata contains, among others, the current optimizer parameters, object statistics, objects identities, the name, the type and the length of the bind variables. The information about the length of the bind variable used during the execution plan compilation is particularly non-innocent. Indeed, anything that breaks the stored bind variable length metadata is going to invalidate the cursor and, thereby, provoke a hard parse of a new execution plan. Within the child cursor metadata Oracle has implemented the following five buffer sizes to store varchar2 bind variable lengths: a buffer for bind variable with less than 32 characters a buffer for bind variable with a length between 33 and 128 characters a buffer for bind variable with a length between 129 and 2000 characters a buffer for bind variable with a length between 2001 and 4000 characters a buffer for bind variable with more than 4000 characters Suppose that you have, first, executed a query using a string bind variable of 10 bytes length and then you rerun the same query but this time using a bind variable of 42 bytes length. During the second execution you used a bind variable length which traverses the first range of buffer size exposed above forcing, thereby, Oracle to hard parse a new execution plan. In order to illustrate this situation I will run the following query five times: SQL> select banner from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production SQL> SELECT count(1) from t1 where v1 = :s1; COUNT(1) ---------- 100 When running the above query I will be using the same bind variable value :s1 but with a different length at each execution. I will start the experiment using a bind variable of a varchar2(10) length which is less than 32 bytes corresponding to the first buffer size category mentioned above: SQL> create table t1 as select rownum n1 ,trunc ((rownum-1)/5) n2 ,case mod(rownum, 100) when 0 then 'Hundred' else 'NotHundred' end v1 from dual connect by level var s1 varchar2( 10 ) SQL> exec :s1 := 'Hundred' SQL> SELECT count(1) from t1 where v1 = :s1; COUNT(1) ---------- 100 SQL> select * from table(dbms_xplan.display_cursor); SQL_ID 1dgh1vt3brm4w, child number 0 ------------------------------------- SELECT count(1) from t1 where v1 = :s1 ------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL | T1 | 5000 | ------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("V1"=:S1) Now, I will use a :s1 bind variable length situated in the second buffer size category (>32 and var s1 varchar2( 33 ) SQL> exec :s1 := 'Hundred' SQL> SELECT count(1) from t1 where v1 = :s1; COUNT(1) ---------- 100 SQL> select * from table(dbms_xplan.display_cursor); SQL_ID 1dgh1vt3brm4w, child number 1 ------------------------------------- SELECT count(1) from t1 where v1 = :s1 ------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL | T1 | 5000 | ------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 – filter("V1"=:S1) Notice how changing the bind variable length from 10 to 33 has forced Oracle to compile a new execution plan represented by the child number 1 . If you want to know the reason for this hard parse then simply run the following script: SQL> @nonshared 1dgh1vt3brm4w Show why existing SQL child cursors were not reused (V$SQL_SHARED_CURSOR)... SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8CFDFDBD8 CHILD_NUMBER : 0 REASON : Bind mismatch(22) 32 128 ----------------- SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8D1EAA548 CHILD_NUMBER : 1 BIND_LENGTH_UPGRADEABLE : Y REASON : Bind mismatch(22 ) 128 32 Oracle is clearly showing that it has been forced to compile a new execution plan because the new length of the s1 bind variable ( original_oacmxl =32 var s1 varchar2( 129 ) SQL> exec :s1 := 'Hundred' SQL> SELECT count(1) from t1 where v1 = :s1; SQL_ID 1dgh1vt3brm4w, child number 2 ------------------------------------- ------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL | T1 | 1 | ------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("V1"=:S1) SQL> var s1 varchar2( 2001 ) SQL> exec :s1 := 'Hundred' SQL> SELECT count(1) from t1 where v1 = :s1; SQL_ID 1dgh1vt3brm4w, child number 3 ------------------------------------- SELECT count(1) from t1 where v1 = :s1 ------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL | T1 | 5000 | ------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("V1"=:S1) SQL> var s1 varchar2( 4001 ) SQL> exec :s1 := 'Hundred' SQL> SELECT count(1) from t1 where v1 = :s1; SQL_ID 1dgh1vt3brm4w, child number 4 ------------------------------------- SELECT count(1) from t1 where v1 = :s1 ------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL | T1 | 5000 | ------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("V1"=:S1) As you can easily point it out, each time I have used a bind variable length that crossed the upper limit of the buffer size interval stored in the previous child cursor metadata, a new execution plan has been generated with he corresponding new buffer size category ( original_oacmxl ) updated accordingly as shown below: SQL> @nonshared 1dgh1vt3brm4w Show why existing SQL child cursors were not reused (V$SQL_SHARED_CURSOR)... SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8CFDFDBD8 CHILD_NUMBER : 0 REASON : Bind mismatch(22 ) 32 128 ----------------- SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8D1EAA548 CHILD_NUMBER : 1 BIND_LENGTH_UPGRADEABLE : Y REASON : Bind mismatch(22) 128 32 ----------------- SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8CFCCB008 CHILD_NUMBER : 2 LANGUAGE_MISMATCH : Y REASON : Bind mismatch(22) 2000 4000 ----------------- SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8CFD5AE20 CHILD_NUMBER : 3 BIND_LENGTH_UPGRADEABLE : Y REASON : Bind mismatch(20 ) 4x4 4000 2000 ----------------- SQL_ID : 1dgh1vt3brm4w ADDRESS : 00007FF8CFDDB148 CHILD_ADDRESS : 00007FF8CFD55290 CHILD_NUMBER : 4 BIND_MISMATCH : Y LANGUAGE_MISMATCH : Y REASON : Bind mismatch(20) 4001 4000 ----------------- STB_OBJECT_MISMATCH Here’s below how Oracle defines this reason ( Y|N ) STB is an internal name for a SQL Management Object Mismatch. A SQL Management Object Mismatch means that either a SQL plan baseline, or a SQL profile, or a SQL patch has been created for your SQL statement between the executions. Because a cursor is a read-only entity, a hard parse is forced to be able to create a new cursor that contains information about the new SQL management object related to this SQL statement. That is one of the best and clear definitions of the g$vsql_shared_cursor reasons I have ever read so far. It explains that when you create a SQL plan baseline or a SQL profile for a SQL statement you want to guaranty its stability, a hard parse is internally forced by Oracle in order to create a new execution plan pre-empting this SQL query from using an unknown and a non-accepted execution plan. Here's below a simple illustration of this reason: SQL> select count(1) from t1 where n1 select * from table(dbms_xplan.display_cursor); SQL_ID d1ztzuajkcz3k , child number 0 ------------------------------------- select count(1) from t1 where n1 declare rs pls_integer; begin rs := dbms_spm.load_plans_from_cursor_cache('d1ztzuajkcz3k'); end; / SQL> select count(1) from t1 where n1 select * from table(dbms_xplan.display_cursor); SQL_ID d 1ztzuajkcz3k , child number 1 ------------------------------------- select count(1) from t1 where n1 @nonshared d1ztzuajkcz3k Show why existing SQL child cursors were not reused (V$SQL_SHARED_CURSOR)... SQL_ID : d1ztzuajkcz3k ADDRESS : 00007FFE7FFAF1B8 CHILD_ADDRESS : 00007FFE81168298 CHILD_NUMBER : 0 REASON : SQL Tune Base Object Different(3) CON_ID : 1 ----------------- SQL_ID : d1ztzuajkcz3k ADDRESS : 00007FFE7FFAF1B8 CHILD_ADDRESS : 00007FFE7FBC9B28 CHILD_NUMBER : 1 REASON : CON_ID : 1 ----------------- Interestingly, when conducting this experiment in several Oracle releases I have realized that the STB_OBJECT_MISMATCH column is not filled up in the 12.1.0.1.0 version of gv$sql_shared_cursor while it is filled up in the 12.1.0.2.0 as shown below respectively: SQL> select sql_id ,child_number ,stb_object_mismatch from gv$sql_shared_cursor where sql_id = 'd1ztzuajkcz3k'; SQL_ID CHILD_NUMBER S ------------- ------------ - d1ztzuajkcz3k 0 N d1ztzuajkcz3k 1 N SQL> select sql_id ,child_number ,stb_object_mismatch from gv$sql_shared_cursor where sql_id = 'd1ztzuajkcz3k'; SQL_ID CHILD_NUMBER S ------------- ------------ - d1ztzuajkcz3k 0 N d1ztzuajkcz3k 1 Y SUMMARY While in the first part of the installment we have explained the LOAD_OPTIMIZER_STATS and the HASH_MATCH_FAILED execution plan non-sharing reasons, in the second part we examined why Oracle has to hard parse a new execution plan when the underlying cursor has been invalidated following a fresh statistics gathering using the default value of the no_invalidate parameter of the dbms_stats package. We have demonstrated in this case that the gv$sql_shared_cursor will show the ROLL_INVALID_MISMATCH as the reason for this execution plan hard parsing. We have then explained the not so obvious TOP_RPI_LEVEL non-sharing reason which kicks in when two identical SQL statement are called from a different depth. Particularly when one is called from SQL while the other is called from a PL/SQL stored procedure. In this article (Part III) we explained the BIND_MISMATCH and the STB_OBJECT_MISMATCH. While the former represents one of the recurrent reasons I have very often observed in SQL code generated from Java applications because of bind variable length variations, the later pops-up whenever a SQL Plan Baseline is created to fix a stable and validated execution plan. With these three articles we covered six reasons among sixty four ones exposed in gv$sql_shared_cursor. Stay tuned several parts will follow.

Viewing all articles
Browse latest Browse all 1814

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>