[转帖]浅谈cursor_sharing取值对SQL共享的影响(下)_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3778 | 回复: 0   主题: [转帖]浅谈cursor_sharing取值对SQL共享的影响(下)        下一篇 
derek
注册用户
等级:中校
经验:1550
发帖:209
精华:0
注册:2011-7-21
状态:离线
发送短消息息给derek 加好友    发送短消息息给derek 发消息
发表于: IP:您无权察看 2011-9-2 15:23:23 | [全部帖] [楼主帖] 楼主

4、FORCE——强制共享执行计划

默认值EXACT的作用是不对非字面SQL绑定变量进行替换操作。而FORCE值和SIMILAR取值意味着Oracle需要对输入的SQL语句进行处理,首先就是对条件值进行绑定变量化,其次就是针对不同的取值采用不同的执行计划共享策略。

当选择FORCE值的时候,意味着Oracle会对SQL字面值进行绑定变量处理。一个语句形成父游标和仅有的一个子游标。子游标执行计划通过Oracle binds peeking技术实现,以后所有类似形态的SQL都是先共享。

SQL> alter system flush shared_pool;
System altered
SQL> alter session set cursor_sharing='FORCE';
Session altered
SQL> select name, value from v$parameter where name='cursor_sharing';
NAME                VALUE
-------------------- --------------------
cursor_sharing      FORCE


将当前会话的cursor_sharing设置为force,同时清空library cache。之后使用三条SQL语句进行试验。

SQL> select count(*) from t where id1='D';
COUNT(*)
----------
10000
SQL> select count(*) from t where id1='P';
COUNT(*)
----------
8000
SQL> select count(*) from t where id1='G';
COUNT(*)
----------
5


如果在EXACT取值的时候,三个执行语句一定会生成三个父游标和三个子游标的。每一个游标对应一个单独的执行计划。第一和第二条SQL对应全表扫描FTS方案较好,而第三条SQL显然索引路径较优。我们看看在FORCE取值的时候,生成计划情况如何呢?

SQL> select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like '%%';
SQL_TEXT                                                                        SQL_ID       VERSION_COUNT EXECUTIONS
-------------------------------------------------------------------------------- ------------- ------------- ----------
select count(*) from t where id1=:"SYS_B_0"    24vkux5z1rsjy            1         3
SQL> select sql_id, child_number, sql_text from v$sql where sql_id='24vkux5z1rsjy';
SQL_ID       CHILD_NUMBER SQL_TEXT
------------- ------------ --------------------------------------------------------------------------------
24vkux5z1rsjy           0select count(*) from t where id1=:"SYS_B_0"


此时,我们观察到三次执行之后SQL游标共享情况。首先,三次的SQL语句从字面值上完全不同,差异只是存在在条件id1取值上。如果在cursor_sharing为EXACT模式下,是不能实现游标共享的。设置为FORCE之后,我们发现Oracle自动将id1=后面的条件替换为绑定变量。三次SQL调用均使用相同的父游标,而子游标只存在一个,意味著三次调用均是使用这个唯一的子游标。一个子游标对应一个执行计划,三个SQL使用相同的执行计划。

我们使用抽取手段抽取出执行计划,如下:

SQL> select * from table(dbms_xplan.display_cursor('24vkux5z1rsjy',0,'advanced'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID 24vkux5z1rsjy, child number 0
-------------------------------------
select count(*) from t where
id1=:"SYS_B_0"
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation         | Name | Rows | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------
|  0 | SELECT STATEMENT  |     |      |      |    9 (100)|         |
|  1 | SORT AGGREGATE   |     |    1 |    2 |           |         |
|* 2 |  TABLE ACCESS FULL| T   | 10000 | 20000 |    9 (12)| 00:00:01 |
---------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T@SEL$1
Peeked Binds (identified by position):
--------------------------------------
1 - :SYS_B_0 (VARCHAR2(30), CSID=852): 'D'
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID1"=:SYS_B_0)
49 rows selected


注意,这个执行计划进行的是数据表的全表扫描。三次调用中,id1取定D\P因为数据量大,都可以使用FTS。但是G取值量少,应该使用索引路径较为合适。所以,在第一次生成执行计划之后,Oracle都会使用该执行计划作为相同SQL结构的语句计划。

这类问题很类似于大名鼎鼎的bind peeking。在执行计划中,我们也的确看到了bind peeking信息,说明其中是使用‘D’值peeking出的执行计划。

此处,我们已经可以知道FORCE取值的效果,当cursor_sharing参数选择FORCE的时候:

üOracle对输入的SQL值,会将where条件取值自动替换为绑定变量。以后在输入相同的结构SQL语句时,会进行cursor sharing共享游标;

ü在第一次进行自动替换绑定变量的时候,Oracle会依据bind peeking取值,获取到一个执行计划,对应成子游标;

ü在以后的SQL语句中,只要出现父游标可共享的情况,Oracle都会强制使用生成的唯一子游标进行sharing。不去在乎是不是对SQL是最优的执行计划;

FORCE取值的规则思想很简单,对SQL语句进行强制的绑定变量替换。使用第一次的bind peeking值生成执行计划,之后全部使用这个执行计划。这种方式实现了游标共享,避免出现大量的library cache硬解析,限制一个父游标的version_count数量。

如果这种SQL语句本身是“Good SQL”,也就是条件列分布比较平均,没有出现过大的偏移分布。我们认为这种FORCE是很有益的。但是如果数据列分布不平均,这样借用第一次输入的bind peeking生成并且共享执行计划就很成问题。我们说,在cursor_sharing取定FORCE遇到的潜在问题,和我们使用绑定变量时候使用的bind peeking值问题是相同的。






赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论