【DB笔试面试585】在Oracle中,什么是常规游标共享?
作者:互联网
在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及其后续的版本)。
下面给出一些游标不能共享的示例:
第一组,表名大小写,空格不同:
1--第一组,表名大小写,空格不同:
2① select * from emp;
3② select * from Emp; --表名大小写不同
4③ select * from EMP;--FROM后比①多了1个空格
5
6--第二组,输入值不同:
7① select * from emp where empno=7369;--输入值不同
8② select * from emp where empno=7788;--输入值不同
9
10--第三组,表所属用户不同:
11① lhr66@lhrdb> select * from t_lhr;--t_lhr属于lhr66用户
12② scott@lhrdb> select * from t_lhr;--t_lhr属于scott用户
13
14--下面给出一个与常规游标共享有关的示例(数据库版本为10.2.0.1):
15--准备相关的表并收集统计信息:
16CREATE TABLE T_CS_20170610 AS SELECT * FROM DBA_OBJECTS;
17CREATE INDEX IDX_OBJ_LHR ON T_CS_20170610(OBJECT_ID);
18EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_CS_20170610',ESTIMATE_PERCENT => 100,CASCADE => TRUE,METHOD_OPT => 'FOR ALL COLUMNS SIZE 1',NO_INVALIDATE => FALSE);--不收集直方图
19
20--查询:
21SYS@ora10g> show parameter cursor_sharing
22
23NAME TYPE VALUE
24------------------------------------ ----------- ------------------------------
25cursor_sharing string EXACT
26
27SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0;
28
29 COUNT(1)
30----------
31 0
32
33SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1;
34
35 COUNT(1)
36----------
37 0
38
39SYS@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=%';
40
41SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
42------------------------------------------------------------ ------------- ------------- ----------
43SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1 gbkpakaxfmbm4 1 1
44SELECT 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:
1SYS@ora10g> ALTER SESSION SET CURSOR_SHARING='SIMILAR';
2
3Session altered.
4
5SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
6
7System altered.
8
9SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0;
10
11 COUNT(*)
12----------
13 0
14
15SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1;
16
17 COUNT(*)
18----------
19 0
20
21SYS@ora10g> col sql_text format a80
22SYS@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=%';
23
24SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
25-------------------------------------------------------------------------------- ------------- ------------- ----------
26SELECT 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:
1SYS@ora10g> ALTER SESSION SET CURSOR_SHARING='FORCE';
2
3Session altered.
4
5SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
6
7System altered.
8
9SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=0;
10
11 COUNT(*)
12----------
13 0
14
15SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=1;
16
17 COUNT(*)
18----------
19 0
20
21SYS@ora10g> col sql_text format a80
22SYS@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=%';
23
24SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
25-------------------------------------------------------------------------------- ------------- ------------- ----------
26SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID=:"SYS_B_0" bgzgahgcxyss7 1 2
现在再来看在不安全的谓词条件下当CURSOR_SHARING的值分别为EXACT、SIMILAR和FORCE时的对比。还是先来看CURSOR_SHARING的值为EXACT的情形:
1SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=EXACT;
2
3Session altered.
4
5SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
6
7System altered.
8
9SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1;
10
11 COUNT(*)
12----------
13 0
14
15SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2;
16
17 COUNT(*)
18----------
19 1
20
21SYS@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%';
22
23SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
24-------------------------------------------------------------------------------- ------------- ------------- ----------
25SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2 g6ygwtg4482r3 1 1
26SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1 7b5sugy5n62gq 1 1
27
28--下面把CURSOR_SHARING修改为SIMILAR:
29SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=SIMILAR;
30
31Session altered.
32
33SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
34
35System altered.
36
37SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1;
38
39 COUNT(*)
40----------
41 0
42
43SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2;
44
45 COUNT(*)
46----------
47 1
48
49--这里若不能使用常规游标共享,则可以多清理几次共享池,另外,执行SQL查询时中间间隔稍微长一点。
50SYS@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%';
51
52SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
53---------------------------------------------------------------------------------------- ------------- ------------- ----------
54SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 2 2
55
56SYS@ora10g> SELECT SQL_TEXT,SQL_ID,D.CHILD_NUMBER,EXECUTIONS,PLAN_HASH_VALUE FROM V$SQL D WHERE SQL_ID = '21371b4zdvrkg';
57
58SQL_TEXT SQL_ID CHILD_NUMBER EXECUTIONS PLAN_HASH_VALUE
59---------------------------------------------------------------------------------------- ------------- ------------ ---------- ---------------
60SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 0 1 3299589416
61SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1" 21371b4zdvrkg 1 1 3299589416
62
63--上述两个Child Cursor所对应的列PLAN_HASH_VALUE的值均为3299589416,说明虽然这里确实产生了两个Child Cursor,但它们存储的执行计划却是相同的。从如下显示内容可以看到,这两个Child Cursor中存储的执行计划确实是相同的(走的均是对索引IDX_OBJ_LHR的索引范围扫描):
64SYS@ora10g> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('21371b4zdvrkg',0,'advanced'));
65
66PLAN_TABLE_OUTPUT
67------------------------------------------------------
68SQL_ID 21371b4zdvrkg, child number 0
69-------------------------------------
70SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND :"SYS_B_1"
71
72Plan hash value: 3299589416
73
74----------------------------------------------------------------------------------
75| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
76----------------------------------------------------------------------------------
77| 0 | SELECT STATEMENT | | | | 2 (100)| |
78| 1 | SORT AGGREGATE | | 1 | 5 | | |
79|* 2 | FILTER | | | | | |
80|* 3 | INDEX RANGE SCAN| IDX_OBJ_LHR | 1 | 5 | 2 (0)| 00:00:01 |
81----------------------------------------------------------------------------------
82
83Query Block Name / Object Alias (identified by operation id):
84-------------------------------------------------------------
85
86 1 - SEL$1
87 3 - SEL$1 / T_CS_20170610@SEL$1
88
89Outline Data
90-------------
91
92 /*+
93 BEGIN_OUTLINE_DATA
94 IGNORE_OPTIM_EMBEDDED_HINTS
95 OPTIMIZER_FEATURES_ENABLE('10.2.0.1')
96 ALL_ROWS
97 OUTLINE_LEAF(@"SEL$1")
98 INDEX(@"SEL$1" "T_CS_20170610"@"SEL$1" ("T_CS_20170610"."OBJECT_ID"))
99 END_OUTLINE_DATA
100 */
101
102Peeked Binds (identified by position):
103--------------------------------------
104
105 1 - :SYS_B_0 (NUMBER): 0
106 2 - :SYS_B_1 (NUMBER): 1
107
108Predicate Information (identified by operation id):
109---------------------------------------------------
110
111 2 - filter(:SYS_B_0<=:SYS_B_1)
112 3 - access("OBJECT_ID">=:SYS_B_0 AND "OBJECT_ID"<=:SYS_B_1)
113
114Column Projection Information (identified by operation id):
115-----------------------------------------------------------
116
117 1 - (#keys=0) COUNT(*)[22]
118
119
12052 rows selected.
121
122SYS@ora10g>
123SYS@ora10g> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('21371b4zdvrkg',1,'advanced'));
124
125PLAN_TABLE_OUTPUT
126----------------------------------------------------------------
127SQL_ID 21371b4zdvrkg, child number 1
128-------------------------------------
129SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN :"SYS_B_0" AND
130:"SYS_B_1"
131
132Plan hash value: 3299589416
133
134----------------------------------------------------------------------------------
135| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
136----------------------------------------------------------------------------------
137| 0 | SELECT STATEMENT | | | | 2 (100)| |
138| 1 | SORT AGGREGATE | | 1 | 5 | | |
139|* 2 | FILTER | | | | | |
140|* 3 | INDEX RANGE SCAN| IDX_OBJ_LHR | 1 | 5 | 2 (0)| 00:00:01 |
141----------------------------------------------------------------------------------
142
143Query Block Name / Object Alias (identified by operation id):
144-------------------------------------------------------------
145
146 1 - SEL$1
147 3 - SEL$1 / T_CS_20170610@SEL$1
148
149Outline Data
150-------------
151
152 /*+
153 BEGIN_OUTLINE_DATA
154 IGNORE_OPTIM_EMBEDDED_HINTS
155 OPTIMIZER_FEATURES_ENABLE('10.2.0.1')
156 ALL_ROWS
157 OUTLINE_LEAF(@"SEL$1")
158 INDEX(@"SEL$1" "T_CS_20170610"@"SEL$1" ("T_CS_20170610"."OBJECT_ID"))
159 END_OUTLINE_DATA
160 */
161
162Peeked Binds (identified by position):
163--------------------------------------
164
165 1 - :SYS_B_0 (NUMBER): 1
166 2 - :SYS_B_1 (NUMBER): 2
167
168Predicate Information (identified by operation id):
169---------------------------------------------------
170
171 2 - filter(:SYS_B_0<=:SYS_B_1)
172 3 - access("OBJECT_ID">=:SYS_B_0 AND "OBJECT_ID"<=:SYS_B_1)
173
174Column Projection Information (identified by operation id):
175-----------------------------------------------------------
176
177 1 - (#keys=0) COUNT(*)[22]
178
179
18052 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;”:
1SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2;
2
3 COUNT(*)
4----------
5 1
6
7SYS@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%';
8
9SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
10---------------------------------------------------------------------------------------- ------------- ------------- ----------
11SELECT 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时不同。
1SYS@ora10g> ALTER SESSION SET CURSOR_SHARING=FORCE;
2
3Session altered.
4
5SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
6
7System altered.
8
9SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
10
11System altered.
12
13SYS@ora10g> ALTER SYSTEM FLUSH SHARED_POOL;
14
15System altered.
16
17SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 0 AND 1;
18
19 COUNT(*)
20----------
21 0
22
23SYS@ora10g> SELECT COUNT(*) FROM T_CS_20170610 WHERE OBJECT_ID BETWEEN 1 AND 2;
24
25 COUNT(*)
26----------
27 1
28
29SYS@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%';
30
31SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
32---------------------------------------------------------------------------------------- ------------- ------------- ----------
33SELECT 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程序员面试笔试宝典》,作者:李华荣。
---------------优质麦课------------
详细内容可以添加麦老师微信或QQ私聊。
● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用
● 作者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列题目来源于作者的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
● QQ:646634621 QQ群:618766405
● 提供OCP、OCM和高可用部分最实用的技能培训
● 题目解答若有不当之处,还望各位朋友批评指正,共同进步
长按下图识别二维码或微信扫描下图二维码来关注小麦苗的微信公众号:xiaomaimiaolhr,学习最实用的数据库技术。
本文分享自微信公众号 - DB宝(lhrdba)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
标签:COUNT,585,OBJECT,DB,游标,20170610,SQL,WHERE,ID 来源: https://blog.51cto.com/lhrbest/2709810