Wednesday, July 13, 2011

CURSOR_SHARING parameter



CURSOR_SHARING is an init.ora parameter which decides whether a SQL send from user is a candidate for fresh parsing or will use an existing plan.

This parameter has 3 values.

1. CURSOR_SHARING = Exact (Default)

Definition: Share the plan only if text of SQL matches exactly with the text of SQL lying in shared pool

Let’s take an example


SQL> create table test1 (t1 number);
Table created.

SQL> insert into test1 values(1);
1 row created.

SQL> insert into test1 values(2);
1 row created.

SQL> commit;
Commit complete.

SQL> select * from test1 where t1=1;

T1
----------
1

SQL> select * from test1 where t1=2;

T1
----------
2

SQL> select sql_text from v$sql  where sql_text like 'select * from test1%'  order by sql_text;

SQL_TEXT
-----------------------------------------------------
select * from test1 where t1=1
select * from test1 where t1=2


As you see there were 2 statements in V$sql, so it generated 2 plans. Oracle had to do the same work again to generate the plan even when the difference between the two SQL was just literal value.


2. CURSOR_SHARING = Force (Introduced in 8.1.6)

Definition: Share the plan (forcibly) of a SQL if the text of SQL matches (except literal values) with text of SQL in shared pool

This means if 2 SQL’s are same except their literal values, share the plan.

Let’s take an example:  
I’m using the same table and data which is used in case of above example.

SQL> alter system flush shared_pool;
System altered.

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

SQL> select * from test1 where t1=1;

T1
----------
1

SQL> select * from test1 where t1=
2;

T1
----------
2

SQL> select sql_text from v$sql where sql_text like 'select * from test1%'   order by sql_text;

SQL_TEXT
---------------------------------------------------
select * from test1 where t1=:"SYS_B_0"


You can see for both the statements there was only one entry in V$SQL This means for second occurrence, oracle did not generate a new plan.

This not only helps in savings DB server engine time for generating the plan but also helps in reducing the number of plans shared pool can hold.

Important note:

Cursor_sharing = force can have some flip behavior as well, so you must be careful to use this. Using this we are forcing oracle to use the same plan for 2(or more) SQL’s even when using the same plan may not be good for similar SQL’s.

Example: “where t1=2” may be a good candidate for index scan while “where t1=10” should use a full table scan because 90% of the rows in the table has t1=10 (assumption).



3. CURSOR_SHARING = SIMILAR (Introduced in 9i)


This is the tricky one, but most used.

Definition: 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. (Source: Oracle documentation)

Let’s understand this.
Re-quoting the example above > “where t1=2” may be a good candidate for index scan while “where t1=10” should use a full table scan because 90% of the rows in the table has t1=10 (assumption).

To avoid 2 statements using the same plan when the same plan is not good for one of them, we have cursor_sharing=similar

Let’s take an example:

SQL> alter system flush shared_pool;
System altered.

SQL> drop table test1;
Table dropped.

SQL> create table test1 (t1 number,t2 number);
Table created.


SQL>  begin
2 for i in 1 .. 100 loop
3 insert into test1 values(1,i);
4 end loop;
5 commit;
6 update test1 set t1=2 where rownum <> /

PL/SQL procedure successfully completed.

In this case t1 has value “2” in first row and “1” in rest 99 rows
SQL> create index tt_indx on test1(t1);
Index created.

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

SQL> select * from test1 where t1=2;
1 row selected.

SQL> select * from test1 where t1=1;
99 rows selected.

SQL> select sql_text from v$sql  where sql_text like 'select * from test1%' order by sql_text;

SQL_TEXT
----------------------------------------------------
select * from test1 where t1=:"SYS_B_0"
select * from test1 where t1=:"SYS_B_0"

This tells us that even though the 2 statements were similar, Oracle opted for a different plan. Now even if you put t1=30 (0 rows), Oracle will create another plan.
SQL> select * from test1 where t1=30; -- (0 rows)

SQL> select sql_text from v$sql where sql_text like 'select * from test1%' order by sql_text;

SQL_TEXT
---------------------------------------------------
select * from test1 where t1=:"SYS_B_0"
select * from test1 where t1=:"SYS_B_0"
select * from test1 where t1=:"SYS_B_0"

This is because the first time when the SQL ran, oracle engine found the literal value as “unsafe” because using the same literal value can cause bad plans for other similar SQL’s. So along with the PLAN, optimizer stored the literal value also. 
This will ensure the reusability of the plan only in case the same lieteral is provided. In case of any change, optimizer will generate a new plan.

But this doesn’t mean that SIMILAR and EXACT are same.

SQL> alter system flush shared_pool;
System altered.

SQL> select * from test1 where t1=2 and t1=22;
no rows selected

SQL> select * from test1 where t1=2 and t1=23;
no rows selected

SQL> select sql_text from v$sql where sql_text like 'select * from test1%' order by sql_text;

SQL_TEXT
--------------------------------------------------------------
select * from test1 where t1=:"SYS_B_0" and t1=:"SYS_B_1"

Optimizer used single plan for both.

Conclusions:

1. Use CURSOR_SHARING=similar only when you have library cache misses and/or most of the SQL statements differ only in literal values
2. CURSOR_SHARING=force/similar significantly reduces the number of plans in shared pool

Note:

1. Oracle does not recommend setting CURSOR_SHARING to FORCE in a DSS environment or if you are using complex queries. Also, star transformation is not supported with CURSOR_SHARING set to either SIMILAR or FORCE

2. Setting CURSOR_SHARING to SIMILAR or FORCE causes an increase in the maximum lengths (as returned by DESCRIBE) of any selected expressions that contain literals (in a SELECT statement). However, the actual length of the data returned does not change.

0 comments:

Post a Comment

Auto Scroll Stop Scroll