Tuesday 7 July 2015

CURSOR_SHARING=SIMILAR and FORCE - some examples

The CURSOR_SHARING parameter basically influences the extent to which SQL statements (or cursors) can be shared.

 The possible values are EXACT which is the default value and SIMILAR and FORCE.

The official definitions of SIMILAR and FORCE are:

cursor_sharing=similar: “Causes statements that may differ in some literals, but are otherwise identical, to share a cursor, unless the literals affect either the meaning of the statement or the degree to which the plan is optimized.”

 cursor_sharing=FORCE: “Forces statements that may differ in some literals, but are otherwise identical, to share a cursor, unless the literals affect the meaning of the statement.”

So basically it means that the SQL statement will be shared even though literals are different as long as it does not affect the execution plan of the statement. This is the case for SIMILAR setting.

The cursor_sharing=SIMILAR parameter has been deprecated in 11gR2 because it has been found that the use of this parameter could potentially have a lot of performance implications related to the number of child cursors created for the single parent. 

 In versions prior to 11g R2, the was a limit on the number of child cursors  which can be associated with a single parent. It was 1024 and once this number was crossed the parent was marked obsolete and this invalidated it was well as all associated child cursors.

 But not having this upper limit was being found to have caused a lot of CPU usage and waits on mutexes and library cache locks in 11gR2  caused by searching the library cache for matching cursors and it was felt that  having many child cursors all associated with one parent cursor could perform much worse than having many parent cursors that would be seen with having the default setting of cursor_sharing = EXACT

 Using this parameter also was bypassing one of the big improvements made in 11g which was Adaptive Cursor Sharing.

Let us examine the behaviour with CURSOR_SHARING set to SIMILAR as opposed to FORCE and note the differences between the two.

SQL> alter system set cursor_sharing='SIMILAR';

System altered.

Let us now run these three SQL statements which are identical in text, but only differ in the LITERAL values

SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SYS';

  SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SYSTEM';

SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SCOTT';

We can see how the three different SQL statements has been transformed into one single SQL statement – note the part – where owner=:”SYS_B_0″ and also the fact that there is only one single SQL_ID.

Oracle has automatically replaced the literal with a bind value.

 SQL>  select sql_id,sql_text from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';

SQL_ID        SQL_TEXT
------------- --------------------------------------------------------------------------------
7qsnvbzwh79tj select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner=:"SYS_B_0"

We see that the SQL statement has been loaded only once and executed 3 times

SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';

SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
7qsnvbzwh79tj            0          3          1           3

Note the number of versions – it is only one – which shows that the SQL statement has been shared.

SQL> select version_count from v$sqlarea where sql_id='7qsnvbzwh79tj';

VERSION_COUNT
-------------
            1

We need to keep in mind however that using inequalities or LIKE etc will not share cursors even if using SIMILAR

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'A%';

SQL>  select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'B%';

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'C%';

Note the child cursors created and also the version count – this shows that even though we were using SIMILAR for cursor sharing, the SQL statement has not been shared.

SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';

SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
4hxkxzpas5hyq            0          1          1           1
4hxkxzpas5hyq            1          1          1           1
4hxkxzpas5hyq            2          1          1           1

SQL> select version_count from v$sqlarea where sql_id='4hxkxzpas5hyq';

VERSION_COUNT
-------------
3

Let us now change the CURSOR _SHARING to FORCE and see what the difference is.

SQL> alter system set cursor_sharing='FORCE';

System altered.

SQL> select /*FORCE*/  distinct owner from myobjects where owner like 'A%';

SQL>  select /* FORCE */  distinct owner from myobjects where owner like 'B%';

SQL> select /* FORCE */  distinct owner from myobjects where owner like 'C%';

Note that there is only one child and the version count is one which shows that this SQL statement has been shared.

SQL> select version_count from v$sqlarea where sql_id='6c4f9xwp19pff';

VERSION_COUNT
-------------
1

SQL>  select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*FORCE*/%';

SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
6c4f9xwp19pff            0          3          1           3

Let us now look at the effect Histograms have on the SIMILAR setting for the cursor_sharing parameter.

The presence of Histogram statistics on a column being used in the WHERE clause can lead to the cursor not being shared because there is the possibility of the optimizer choosing different plans for different values. In that case we will see multiple children being created as in the example below.

The CBO considers these literals to be UNSAFE

In this case we have created an index on the OBJECT_TYPE column and when we have gathered statistics for the table, Oracle has created histograms for that indexed column.

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='A';

no rows selected

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='B';

no rows selected

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='C';

no rows selected

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='D';

no rows selected

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='E';
no rows selected

SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';

SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
2m80tr9fhhbwn            0          1          1           1
2m80tr9fhhbwn            1          1          1           1
2m80tr9fhhbwn            2          1          1           1
2m80tr9fhhbwn            3          1          1           1
2m80tr9fhhbwn            4          1          1           1

SQL>  select version_count from v$sqlarea where sql_id='2m80tr9fhhbwn';

VERSION_COUNT
-------------
            5

Let us now verify why the cursor was not shared.

SQL> select hash_value,address from v$sqlarea where sql_text like 'select /*TEST_SIMILAR*/%';

HASH_VALUE ADDRESS
---------- ----------------
1560817556 0000000095B58FD8

SQL> select * from v$sql_shared_cursor where address='0000000095B58FD8';

SQL_ID        ADDRESS          CHILD_ADDRESS    CHILD_NUMBER U S O O S L F E B P I S T A B D L T B I I R L I O E M U T N F A I T D L D B P C S C P T M B M R O P M F L P L A F L R L H P B
------------- ---------------- ---------------- ------------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2m80tr9fhhbwn 0000000095B58FD8 000000009160F6B8            0 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 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 N
2m80tr9fhhbwn 0000000095B58FD8 0000000091633E68            1 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 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 Y N N
2m80tr9fhhbwn 0000000095B58FD8 0000000091741E10            2 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 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 Y N N
2m80tr9fhhbwn 0000000095B58FD8 000000008DA39108            3 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 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 Y N N
2m80tr9fhhbwn 0000000095B58FD8 00000000947D5B30            4 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 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 Y N N

We can see that the reason for the cursor not being shared is because of the ‘Y’ in the HASH_MATCH_FAILED column.

Note that this is a new column added to the V$SQL_SHARED_CURSOR view in 11gR2 . In this particular case is it because of the mismatched histogram data

Let us look at another case where cursors are not shared because of what is called a STB_OBJECT_MISMATCH case.

STB_OBJECTS refers to SQL Management Objects like SQL Profiles and SQL Plan Baselines.

If we are using SQL Plan Baselines then we see a new child cursor being created between the first and second executions of the SQL statement because a new SQL Management Object (in this case baseline) was created invalidating the cursor and causing a hard parse the next time the same SQL was executed .

In this example, with cursor_sharing=SIMILAR, because we are using SQL PLan Baselines, a new SQL PLan Management Object was created which invalidated the existing child cursor causing a new child cursor to created for the same parent.

We can see that for the second child, a SQL PLan Baseline was used which was not in the case of the first child.

SQL> select /*TEST_SIMILAR*/  count(*) from myobjects where owner='SYS';

  COUNT(*)
----------
     31129

SQL> select /*TEST_SIMILAR*/  count(*) from myobjects where owner='SYSTEM';

  COUNT(*)
----------
       539

SQL> select /*TEST_SIMILAR*/  count(*) from myobjects where owner='CTXSYS';

  COUNT(*)
----------
       366

SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';

SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
68rgrrrpfas96            0          2          1           2
68rgrrrpfas96            1          1          1           1

SQL> select version_count from v$sqlarea where sql_id='68rgrrrpfas96';

VERSION_COUNT
-------------
            2

SQL> select hash_value,address from v$sqlarea where sql_text like 'select /*TEST_SIMILAR*/%';

HASH_VALUE ADDRESS
---------- ----------------
3940901158 0000000096498EA0

SQL> select * from v$sql_shared_cursor where address='0000000096498EA0';

SQL_ID        ADDRESS          CHILD_ADDRESS    CHILD_NUMBER U S O O S L F E B P I S T A B D L T B I I R L I O E M U T N F A I T D L D B P C S C P T M B M R O P M F L P L A F L R L H P B
------------- ---------------- ---------------- ------------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68rgrrrpfas96 0000000096498EA0 0000000099A374D0            0 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 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 N
68rgrrrpfas96 0000000096498EA0 0000000094546818            1 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 N N N N N N N N N Y N N N N N N N N N N N N N N N N N N N N N N

SQL> select child_number,sql_profile,sql_plan_baseline from v$sql where sql_id='7qsnvbzwh79tj';

CHILD_NUMBER SQL_PROFILE                                                      SQL_PLAN_BASELINE
------------ ---------------------------------------------------------------- ------------------------------
           0
           1                                                                  SQL_PLAN_3m43x2gkdvd0vcaeddc3c

SQL> show parameter baseline

NAME                                 TYPE                             VALUE
------------------------------------ -------------------------------- ------------------------------
optimizer_capture_sql_plan_baselines boolean                          TRUE
optimizer_use_sql_plan_baselines     boolean                          TRUE

No comments:

Post a Comment