【DB笔试面试585】在Oracle中,什么是常规游标共享?
- 2019 年 10 月 10 日
- 筆記
♣
题目部分
在Oracle中,什么是常规游标共享?
♣
答案部分
游标共享(Cursor Sharing)是指共享游标(Shared Cursor)之间的共享,游标共享可以实现重用存储在子游标(Child Cursor)中的解析树和执行计划而不用从头开始做硬解析,从而提高系统性能。特别对于同一类型的目标SQL更应该实现游标共享,而使用绑定变量就可以实现游标共享。
由于很多OLTP类型的应用系统的开发人员在开发阶段并未意识到硬解析的危害,所以也没有使用绑定变量,等到系统上线后才发现问题。此时若要使用绑定变量,则意味着绝大多数SQL都得改写,但这个代价就太大了,所以Oracle引入了常规游标共享。
即使应用系统在开发阶段使用了绑定变量,但在默认情况下也会受到绑定变量窥探的影响。绑定变量窥探的副作用在于,一旦启用(默认情况下绑定变量窥探就已经被启用),使用了绑定变量的目标SQL就只会沿用之前硬解析时所产生的解析树和执行计划,即使这种沿用完全不适合当前的情形,为了解决这个问题,Oracle引入了自适应游标共享。
先介绍一下与本小节相关的几个概念:
l 安全的谓词条件是指如果一个谓词条件所在的目标SQL的执行计划并不随该谓词条件的输入值的变化而变化,那么该谓词条件就是安全的。比如,对于主键列施加等值查询的谓词条件,无论传入的主键值是什么,其执行计划都会是固定的,不会变化。
l 不安全的谓词条件是指如果目标SQL的执行计划可能会随着谓词条件的输入值的不同而发生变化,那么该谓词条件就是一个不安全的谓词条件。Oracle数据库中典型的不安全的谓词条件有范围查询(使用了>、>=、<、<=、BETWEEN的谓词条件),使用了带通配符(%)的LIKE,以及对有直方图统计信息的目标列施加的等值查询等。
l 同一类型SQL是指除SQL文本中对应的输入值不同外,其它部分都一模一样的目标SQL,例如,“SELECT ENAME FROM EMP WHERE EMPNO=7369”和“SELECT ENAME FROM EMP WHERE EMPNO=7370”就是同一类型的SQL。
下面分别来介绍常规游标共享和自适应游标共享这两个方面。
1、 常规游标共享
常规游标共享是在Oracle 8i中引入的。常规游标共享可以做到既有效降低系统硬解析的数量,又对应用透明,即常规游标共享可以做到在应用不改一行代码的情况下,使那些仅仅是SQL文本中的WHERE条件或者INSERT语句的VALUES子句中的具体输入值不同的目标SQL彼此之间共享解析树和执行计划。当开启了常规游标共享后,Oracle在实际解析目标SQL之前,会先用系统产生的绑定变量来替换目标SQL的SQL文本中WHERE条件或者INSERT中的VALUES子句中的具体输入值,这样替换后实际执行的SQL就己经是使用了绑定变量的改写后的等价SQL。Oracle数据库里系统产生的绑定变量的命名规则是“:"SYS_B_n"(n=0,1,2,……)”。例如,原目标SQL为“SELECT ENAME FROM EMP WHERE EMPNO=7369”,如果开启了常规游标共享,那么Oracle做替换后的等价改写形式就是“SELECT ENAME FROM EMP WHERE EMPNO=:"SYS_B_0"”。
Oracle数据库中的常规游标共享受参数CURSOR_SHARING的控制,其值可以被设置为EXACT、SIMILAR或FORCE,它们各自的含义如下所示:
l EXACT表示Oracle不会用系统产生的绑定变量来替换目标SQL的SQL文本中WHERE条件或者INSERT语句的VALUES子句中的具体输入值,EXACT是CURSOR_SHARING的默认值。
l SIMILAR表示Oracle会用系统产生的绑定变量来替换目标SQL的SQL文本中WHERE条件或者INSERT语句的VALUES子句中的具体输入值。在这种情况下,Oracle只会对那些它认为是安全的谓词条件在替换后重用解析树和执行计划,对于它认为的不安全的谓词条件,即便用系统产生的绑定变量替换后的SQL文本是一模一样的,对于每一个不同的输入值,Oracle都会执行一次硬解析,即此时会出现一个Parent Cursor下挂一堆Child Cursor的现象,而这些Child Cursor中存储的解析树和执行计划很可能是一样的(需要注意的是,因为自适应游标共享的引入,这种行为不再适用于Oracle 11g及其后续的版本)。在Oracle 12c以及后续的版本中SIMILAR将过时,不再被继续支持。因为当CURSOR_SHARING设成SIMILAR后会带来一系列的问题,并且有太多与SIMILAR相关的Bug。
l FORCE和SIMILAR一样,FORCE表示Oracle会用系统产生的绑定变量来替换目标SQL的SQL文本中WHERE条件或者INSERT语句的VALUES子句中的具体输入值。但和SIMILAR不同的是,当CURSOR_SHARING的值为FORCE时,替换后同一类型的SQL总是会无条件地重用之前硬解析时的解析树和执行计划(需要注意的是,因为自适应游标共享的引入,这种行为不再适用于Oracle 11g及其后续的版本)。
下面给出一些游标不能共享的示例:
第一组,表名大小写,空格不同:
--第一组,表名大小写,空格不同: ① select * from emp; ② select * from Emp; --表名大小写不同 ③ select * from EMP;--FROM后比①多了1个空格 --第二组,输入值不同: ① select * from emp where empno=7369;--输入值不同 ② select * from emp where empno=7788;--输入值不同 --第三组,表所属用户不同: ① lhr66@lhrdb> select * from t_lhr;--t_lhr属于lhr66用户 ② scott@lhrdb> select * from t_lhr;--t_lhr属于scott用户 --下面给出一个与常规游标共享有关的示例(数据库版本为10.2.0.1): --准备相关的表并收集统计信息: CREATE TABLE T_CS_20170610 AS SELECT * FROM DBA_OBJECTS; CREATE INDEX IDX_OBJ_LHR ON T_CS_20170610(OBJECT_ID); EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_CS_20170610',ESTIMATE_PERCENT => 100,CASCADE => TRUE,METHOD_OPT => 'FOR ALL COLUMNS SIZE 1',NO_INVALIDATE => FALSE);--不收集直方图 --查询: SYS@ora10g> show parameter cursor_sharing NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ cursor_sharing string EXACT SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0; COUNT(1) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1; COUNT(1) ---------- 0 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ------------------------------------------------------------ ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1 gbkpakaxfmbm4 1 1 SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0 f9uyh6hyf7kcc 1 1
现在CURSOR_SHARING的值为EXACT,所以Oracle不会用系统产生的绑定变量来替换上述SQL的WHERE条件中的输入值,而上述两个SQL的WHERE条件中的输入值并不相同(一个是0,另一个是1),即意味着这两个SQL在执行时均会使用硬解析。
对于上述两个SQL而言,其谓词条件均为“OBJECT_ID=XXX”,这是一个等值查询条件,同时目标列OBJECT_ID上没有直方图统计信息,所以该谓词条件是一个安全的谓词条件。也就是说,如果把CURSOR_SHARING的值改为SIMILAR后再次执行这两个SQL,那么Oracle就会用系统产生的绑定变量来替换上述谓词条件中的输入值,这意味着当执行“SELECT COUNT(1) FROM T_CS_20170610 WHERE OBJECT_ID=1”时,Oracle会沿用之前执行“SELECT COUNT(1) FROM T_CS_20170610 WHERE OBJECT_ID=0”所对应的解析树和执行计划。
下面把CURSOR_SHARING修改为SIMILAR:
SYS@ora10g> ALTER SESSION SET CURSOR_SHARING='SIMILAR'; Session altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0; COUNT(*) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1; COUNT(*) ---------- 0 SYS@ora10g> col sql_text format a80 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS -------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=:"SYS_B_0" bgzgahgcxyss7 1 2
注意,列VERSION_COUNT的值为1,列EXECUTIONS的值为2,这说明在目标SQL的谓词条件是安全的谓词条件,且CURSOR_SHARING的值为SIMILAR的前提条件下,Oracle确实会重用之前硬解析时所对应的解析树和执行计划。
由于上述两个SQL的谓词条件是安全的谓词条件,因此把CURSOR_SHARING的值改为SIMILAR或者FORCE并没有什么区别,即如果把CURSOR_SHARING的值改为FORCE后再次执行这两个SQL,所得到的结果应该和CURSOR SHARING的值为SIMILAR时一样。
来验证一下把CURSOR_SHARING的值改为FORCE,并再次执行这两个SQL:
SYS@ora10g> ALTER SESSION SET CURSOR_SHARING='FORCE'; Session altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0; COUNT(*) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1; COUNT(*) ---------- 0 SYS@ora10g> col sql_text format a80 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS -------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=:"SYS_B_0" bgzgahgcxyss7 1 2
现在再来看在不安全的谓词条件下当CURSOR_SHARING的值分别为EXACT、SIMILAR和FORCE时的对比。还是先来看CURSOR_SHARING的值为EXACT的情形:
SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=EXACT; Session altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1; COUNT(*) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2; COUNT(*) ---------- 1 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS -------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2 g6ygwtg4482r3 1 1 SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1 7b5sugy5n62gq 1 1 --下面把CURSOR_SHARING修改为SIMILAR: SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=SIMILAR; Session altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1; COUNT(*) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2; COUNT(*) ---------- 1 --这里若不能使用常规游标共享,则可以多清理几次共享池,另外,执行SQL查询时中间间隔稍微长一点。 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ---------------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 2 2 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,D.CHILD_NUMBER,EXECUTIONS,PLAN_HASH_VALUE FROM V$SQL D WHERE SQL_ID = '21371b4zdvrkg'; SQL_TEXT SQL_ID CHILD_NUMBER EXECUTIONS PLAN_HASH_VALUE ---------------------------------------------------------------------------------------- ------------- ------------ ---------- --------------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 0 1 3299589416 SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 1 1 3299589416 --上述两个Child Cursor所对应的列PLAN_HASH_VALUE的值均为3299589416,说明虽然这里确实产生了两个Child Cursor,但它们存储的执行计划却是相同的。从如下显示内容可以看到,这两个Child Cursor中存储的执行计划确实是相同的(走的均是对索引IDX_OBJ_LHR的索引范围扫描): SYS@ora10g> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('21371b4zdvrkg',0,'advanced')); PLAN_TABLE_OUTPUT ------------------------------------------------------ SQL_ID 21371b4zdvrkg, child number 0 ------------------------------------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" Plan hash value: 3299589416 ---------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 5 | | | |* 2 | FILTER | | | | | | |* 3 | INDEX RANGE SCAN| IDX_OBJ_LHR | 1 | 5 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 3 - SEL$1 / T_CS_20170610@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('10.2.0.1') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX(@"SEL$1" "T_CS_20170610"@"SEL$1" ("T_CS_20170610"."OBJECT_ID")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - :SYS_B_0 (NUMBER): 0 2 - :SYS_B_1 (NUMBER): 1 Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(:SYS_B_0<=:SYS_B_1) 3 - access("OBJECT_ID">=:SYS_B_0 AND "OBJECT_ID"<=:SYS_B_1) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 52 rows selected. SYS@ora10g> SYS@ora10g> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('21371b4zdvrkg',1,'advanced')); PLAN_TABLE_OUTPUT ---------------------------------------------------------------- SQL_ID 21371b4zdvrkg, child number 1 ------------------------------------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" Plan hash value: 3299589416 ---------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 5 | | | |* 2 | FILTER | | | | | | |* 3 | INDEX RANGE SCAN| IDX_OBJ_LHR | 1 | 5 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 3 - SEL$1 / T_CS_20170610@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('10.2.0.1') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX(@"SEL$1" "T_CS_20170610"@"SEL$1" ("T_CS_20170610"."OBJECT_ID")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - :SYS_B_0 (NUMBER): 1 2 - :SYS_B_1 (NUMBER): 2 Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(:SYS_B_0<=:SYS_B_1) 3 - access("OBJECT_ID">=:SYS_B_0 AND "OBJECT_ID"<=:SYS_B_1) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 52 rows selected.
这是很不合理的,也是CURSOR_SHARING的值被设为SIMILAR后的主要弊端之一。将CURSOR_SHARING的值设为SIMILAR的目的是想在应用不改一行代码的情形下,使那些仅仅是SQL文本中的WHERE条件或者VALUES子句(适用于INSERT语句)的具体输入值不同的目标SQL彼此之间共享解析树和执行计划,以达到有效降低系统硬解析数量的目的。但在Oracle l1g之前,CURSOR_SHARING的值被设为SIMILAR后你可能会发现这么做的效果有限,系统硬解析的数量并未得到大幅度的降低,而且会出现一个Parent Cursor下挂一堆Child Cursor的现象,而这些Child Cursor中存储的解析树和执行计划很可能是一样的。
以上述两个SQL为例,在当前条件下,“SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1”和“SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2”的执行计划是一样的,显然它们本应共享解析树和执行计划,但就是因为CURSOR_SHARING的值被设为SIMILAR,外加这两个SQL使用的是不安全的谓词条件,所以就导致Oracle在执行它们时均使用了硬解析。
在Oracle 10g及其后续的版本中,Oracle会自动收集直方图统计信息,这意味着在Oracle 10g及其后续的版本中出现不安全的谓词条件的概率要大大高于Oracle 10g之前的版本,所以在Oracle 10g里不要将CURSOR_SHARING的值设成SIMILAR,因为很可能达不到在不改一行应用代码的情形下有效降低系统硬解析数量的目的(更何况还可能会因此而引入一堆Bug)。
在Oracle 11g里也不要将CURSOR_SHARING的值设成SIMILAR,因为在Oracle 11g里自适应游标共享已经被默认启用了,在自适应游标共享被启用的情形下,Oracle并不推荐将CURSOR_SHARING的值设为SIMILAR(参见MOS上的文章"FAQ:Adaptive Cursor Shanng(ACS)Frequently Asked Questions(ID 1518681.1)”。
再次执行SQL语句“SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2;”:
SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2; COUNT(*) ---------- 1 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ---------------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 2 3
从查询结果可以看到列VERSION_COUNT的值还是2,但列EXECUTIONS的值己经从之前的2变为现在的3,说明在目标SQL的谓词条件是不安全的谓词条件,且CURSOR_SHARING的值为SIMILAR的前提条件下,只有针对该谓词条件的当前输入值和之前的输入值完全相同时,Oracle才会重用之前该输入值所对应的解析树和执行计划。
上述两个SQL的谓词条件虽然是不安全的,但不管是“安全的谓词条件”还是“不安全的谓词条件”,当把CURSOR_SHARING的值设为FORCE后,Oracle总是会无条件重用目标SQL之前硬解析时的解析树和执行计划(仅适用于Oracle 11g之前的版本)。所以如果把CURSOR_SHARING的值设为FORCE后再次执行这两个SQL,那么得到的结果应和之前CURSOR_SHARING的值为SIMILAR时不同。
SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=FORCE; Session altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL; System altered. SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1; COUNT(*) ---------- 0 SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2; COUNT(*) ---------- 1 SYS@ora10g> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM V$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ---------------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 1 2
上述显示内容中列VERSION_COUNT的值为1,列EXECUTIONS的值为2,说明即使目标SQL的谓词条件是不安全的,只要CURSOR_SHARING的值为FORCE,那么Oracle就会无条件地重用之前硬解析时对应的解析树和执行计划(仅适用于Oracle l1g之前的版本)。
从上述整个测试过程可以得到如下结论。
l SIMILAR是一个即将过时的值,它有太多的副作用,无论什么时候都不要将CURSOR_SHARING的值设为SIMILAR。
l 如果想在不改一行应用代码的情况下,使那些仅仅是SQL文本中的WHERE条件或者VALUES子句(适用于INSERT语句)中的具体输入值不同的目标SQL共享解析树和执行计划,以达到有效降低系统硬解析数量的目的,那就将CURSOR_SHARING的值设成FORCE吧,虽然这不是最理想的方案(最理想的方案当然还是修改应用的代码,在SQL语句里使用绑定变量,并且尽可能使用批量绑定),但这也许是最省事的方案。
本文选自《Oracle程序员面试笔试宝典》,作者:李华荣。