Cursor_sharing参数有3个值可以设置:
1)、EXACT:通常来说,exact值是Oracle推荐的,也是默认的,它要求SQL语句在完全相同时才会重用,否则会被重新执行硬解析操作。
2)、SIMILAR:similar是在Oracle认为某条SQL语句的谓词条件可能会影响到它的执行计划时,才会被重新分析,否则将重用SQL。
3)、FORCE:force是在任何情况下,无条件重用SQL。
先来测试一下这三种情况的区别:
实验环境:
oracle 11.2.0.3
建立测试表T1:
SQL> create table t1 as select object_id as id,object_name from dba_objects where rownum<=10000;
SQL> create table t1_exact as select * from t1;
SQL> create table t1_similar as select * from t1;
SQL> create table t1_force as select * from t1;
建立一张测试表,并在id列添加索引。
1.当cursor_sharing值为exact时,它要求SQL语句在完全相同时才会重用,否则会被重新执行硬解析操作。
SQL> alter session set cursor_sharing=exact;
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> select * from t1_exact where id=1;
no rows selected
SQL> select * from t1_exact where id=2;
ID
----------
OBJECT_NAME
--------------------------------------------------------------------------------
2
C_OBJ#
SQL> select * from t1_exact where id=1;
no rows selected
SQL> alter session set sql_trace=false;
Session altered.
通过tkprof查看一下这样的语句被硬解析了几次?
select *
from
t1_exact where id=1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 39 80 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 6 0.00 0.00 39 80 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 2
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 TABLE ACCESS FULL T1_EXACT (cr=40 pr=20 pw=0 time=1312 us cost=13 size=22 card=1)
谓词where id=1这条语句被执行了2次(execute),硬解析1次(misses in library cache during parse)
SQL ID: 6a6djdhd16kt0 Plan Hash: 2784782265
select *
from
t1_exact where id=2
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 41 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 41 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS FULL T1_EXACT (cr=41 pr=0 pw=0 time=31 us cost=13 size=22 card=1)
谓词where id=2这条语句被执行了1次(execute),硬解析1次(misses in library cache during parse)
可以看出,exact要求SQL完全一样才被重用。
2.对于SIMILAR的情况,如果CBO发现被绑定变量的谓词还有其他的执行计划可以选择时,如果谓词条件的值有变化,就将会产生一个新的子游标,而不是重用之前的SQL;如果谓词没有其他的执行计划可选择,则忽略谓词的值,重用之前的SQL。
为了测试similar的情况,需要对表增加一行数据,并且增加一个索引以便于说明:
SQL> insert into t1_similar values(3,'TEST');
1 row created.
SQL> create index i_t1_similar on t1_similar(id);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t1_similar',cascade=>true);
PL/SQL procedure successfully completed.
SQL> select * from t1_similar where id between 3 and 5;
ID OBJECT_NAME
---- --------------------
3 I_OBJ#
3 TEST
4 TAB$
5 CLU$
SQL> alter system flush shared_pool; --刷新一下share pool,否则有可能会影响硬解析的准确性
System altered.
接着开始执行sql,后面抓取trace:
SQL> alter session set cursor_sharing=similar;
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> select * from t1_similar where id=4;
ID OBJECT_NAME
---- --------------------
4 TAB$
SQL> select * from t1_similar where id=5;
ID OBJECT_NAME
---- --------------------
5 CLU$
SQL> select * from t1_similar where id=3 and object_name='I_OBJ#';
ID OBJECT_NAME
---- --------------------
3 I_OBJ#
SQL> select * from t1_similar where id=3 and object_name='TEST';
ID OBJECT_NAME
---- --------------------
3 TEST
SQL> alter session set sql_trace=false;
Session altered.
通过trkprof来查看生成的报告:
[oracle@qht131 trace]$ tkprof orcl_ora_2339.trc out.txt sys=no
select *
from
t1_similar where id=:"SYS_B_0"
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.01 0 41 0 0
Execute 1 0.00 0.01 0 0 0 0
Fetch 2 0.00 0.00 0 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.03 0 45 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID T1_SIMILAR (cr=4 pr=0 pw=0 time=33 us cost=2 size=22 card=1)
1 1 1 INDEX RANGE SCAN I_T1_SIMILAR (cr=3 pr=0 pw=0 time=28 us cost=1 size=0 card=1)(object id 78507)
********************************************************************************
SQL ID: 3ys4crhf25cgx Plan Hash: 1128109430
select *
from
t1_similar where id=:"SYS_B_0"
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 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 4 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID T1_SIMILAR (cr=4 pr=0 pw=0 time=34 us cost=2 size=22 card=1)
1 1 1 INDEX RANGE SCAN I_T1_SIMILAR (cr=3 pr=0 pw=0 time=31 us cost=1 size=0 card=1)(object id 78507)
********************************************************************************
当查询谓词分别为id=4和id=5时,分别都进行了硬解析(messes in library chche during parse:1)
SQL ID: ghf6gwn79fas0 Plan Hash: 1128109430
select *
from
t1_similar where id=:"SYS_B_0" and object_name=:"SYS_B_1"
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 4 0.00 0.00 0 10 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 8 0.00 0.00 0 10 0 2
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 2
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID T1_SIMILAR (cr=5 pr=0 pw=0 time=40 us cost=2 size=22 card=1)
2 2 2 INDEX RANGE SCAN I_T1_SIMILAR (cr=3 pr=0 pw=0 time=24 us cost=1 size=0 card=1)(object id 78507)
紧接着,当谓词为 id=3 and object_name='I_OBJ#'和 id=3 and object_name='TEST'时,报告里只有一条sql记录,记录了硬解析1次,不过execute为2,说明执行了2次。这里为什么没有2次硬解析?是因为这object_name的值发生了改变,但是id的值没有发生变,而id上有索引的,object_name上没有索引,CBO认为这样的情况不会改变SQL的执行计划。
3.最后是force的情况:
SQL> alter session set cursor_sharing=force;
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> select * from t1_force where id=2;
ID OBJECT_NAME
---- --------------------
2 C_OBJ#
SQL> select * from t1_force where id=3;
ID OBJECT_NAME
---- --------------------
3 I_OBJ#
SQL> select * from t1_force where id=4;
ID OBJECT_NAME
---- --------------------
4 TAB$
SQL> select * from t1_force where id=1;
no rows selected
SQL> select * from t1_force where id=4;
ID OBJECT_NAME
---- --------------------
4 TAB$
SQL> alter session set sql_trace=false;
Session altered.
通过tkprof查看转义的信息:
SQL ID: f4wtdmc9wwj5g Plan Hash: 3904548038
select *
from
t1_force where id=:"SYS_B_0"
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 5 0.00 0.01 0 0 0 0
Execute 5 0.00 0.00 0 0 0 0
Fetch 9 0.00 0.04 39 204 0 4
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 19 0.00 0.05 39 204 0 4
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS FULL T1_FORCE (cr=41 pr=13 pw=0 time=242 us cost=13 size=22 card=1)
这里只有一个sql id,这条sql执行了5次(execute为5),force的情况下所有sql都无条件地重用sql。
总结:
FORCE和SIMIALR最大的区别在于,FORCE会把所有的谓词用变量代替,并且不管变量的值如何,一律重用第一条SQL语句,而SIMILAR会根据谓词的不同,来重新选择SQL的执行计划。
如果一个系统,它存在变量绑定的问题,并且这种问题已经影响到了系统的性能,这时候可以考虑将参数cursor_sharing的值设置为SIMILAR或FORCE来改善这种局面,不过在改成SIMILAR或FORCE都可能带来一些Bug以及很多未知的东西,所以需要慎用。
最后需要说明一点,对于OLTP系统,如果绑定变量情况不好的话,也许可以考虑通过设置这个参数来缓解一下问题;对于是在OLAP系统上,这个参数应该设置成EXACT,并且不应该使用绑定变量,因为在OLAP系统中,SQL的解析对于SQL的执行来看,话费的代价几乎可以忽略,而正确的SQL执行计划才是OLAP数据库最需要关注的。