Cursor_sharing=SIMILAR取值与直方图(上)

 

从业界普遍接受绑定变量、硬解析和软解析概念以及对Oracle数据库性能的影响之后。开发和运维DBA就都在寻找一种方法,将系统中已经存在和即将存在的硬编码改为绑定变量方式,进而减少硬解析的出现。

 

Cursor_sharing参数在一个时期似乎是解决一切的万灵药。该参数的“作用域”仅限在那些没有使用过绑定变量的SQL语句。这一点很重要,因为如果在系统中使用了绑定变量,这个问题就不是我们需要考虑的了。

 

Cursor_sharing从参数语义上看,就是处理没有使用绑定变量时候,Oracle是否将where后面取值替换为绑定变量,便于进行SQL语句shared cursor共享。

 

参数cursor_sharing具有三个取值:exactsimilarforceEXACT是各Oracle版本参数的默认值,表示不开启这个功能。对没使用绑定变量的SQL语句,完全使用字面值共享机制。FORCE是一个极端,首先会将字面值进行替换,之后所有的执行语句均是采用相同的执行计划。详细解析请参见笔者《浅谈cursor_sharing》(http://space.itpub.net/17203031/viewspace-705196

 

Similar是三个取值中较为复杂的一个。首先,同FORCE取值一样,对传入的SQL语句字面值进行改写,将where条件后的条件取值替换为绑定变量。但同时,SIMILAR并不是强令使用一个子游标满足所有的SQL语句,而是准备多条执行计划与之对应。

 

1、一条SQL需要几个执行计划对应?

 

当一个SQLwhere条件取值被替换为绑定变量,如果按照CBO的原则,不同的绑定变量取值最优的执行计划是不同的。这里我们分为两种情况:

 

ü        Safe SQL

 

如果SQL条件使用的是等号“=”条件,而且数据列分布比较平均,且Oracle存在多种执行计划生成可能的情况下,我们说单执行计划的确可以满足所有SQL等号取值条件。

 

实际中这种数据列比如主键列、唯一索引列和一些统计量反映的平均化。

 

ü        Unsafe SQL

 

Unsafe SQL的情况要复杂的多。当我们的SQL对应条件列是一个数据偏移度很高的列,或者进行范围查询的时候,多个最优执行计划对应的情况是可能出现的。

 

cursor_sharing参数取定SIMILAR的时候,就是可以对“Safe SQL”取定单一执行计划,而对“Unsafe SQL”取定多执行计划。

 

那么,Oracle怎么知道这个SQL是否是Safe呢?下面我们依据实例进行试验。

 

 

2、环境准备

 

我们选择在Oracle 10g下进行试验。

 

 

SQL> select * from v$version;

 

BANNER

----------------------------------------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE     10.2.0.1.0       Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 – Production

 

--默认情况下,cursor_sharing参数取值为EXACT

SQL> show parameter cursor_sharing

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

cursor_sharing                       string      EXACT

 

SQL> select name, type , value from v$parameter where name='cursor_sharing';

NAME                       TYPE VALUE

-------------------- ---------- ----------

cursor_sharing                2 EXACT

 

 

此时,我们构建数据表,取值相同,但是具有不同的数据字典描述内容。从而验证是不是数据字典信息是SIMILAR判定Safe SQL的标准。

 

 

SQL> create table t as select object_id id1, object_id id2, object_id id3 from dba_objects;

Table created

 

SQL> alter table t add constraint pk_t_id1 primary key (id1);

Table altered

 

SQL> create unique index idx_t_id2 on t(id2);

Index created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true,method_opt => 'for all columns size auto');

PL/SQL procedure successfully completed

 

SQL> select column_name, num_distinct, NUM_BUCKETS, HISTOGRAM from dba_tab_col_statistics where wner='SYS' and table_name='T';

 

COLUMN_NAME                    NUM_DISTINCT NUM_BUCKETS HISTOGRAM

------------------------------ ------------ ----------- ---------------

ID1                                   51697           1 NONE

ID2                                   51697           1 NONE

ID3                                   53196           1 NONE

 

 

三个数据列取值完全相同,差异只在于数据字典的描述地位不同。同时,三个列均没有收集标识数据偏移度的直方图。

 

3、无直方图下的相关实验

 

我们首先进行三个数据列试验,判断SIMILAR取值的行为方式。

 

--调整cursor_sharing取值

SQL> alter session set cursor_sharing='SIMILAR';

Session altered

 

SQL> select name, type , value from v$parameter where name='cursor_sharing';

NAME                       TYPE VALUE

-------------------- ---------- --------------------

cursor_sharing                2 SIMILAR

 

 

首先对主键列进行选择使用。

 

--第一次调用SQL

SQL> select /*+ demo_id1 */ count(*) from t where id1=1000;

 

  COUNT(*)

----------

         1

 

--检查父子游标情况

SQL> select sql_text, sql_id, version_count from v$sqlarea where sql_text like 'select /*+ demo_id1 */%';

 

SQL_TEXT             SQL_ID        VERSION_COUNT

-------------------- ------------- -------------

select /*+ demo_id1  bvdkhydtduzb6             1

*/ count(*) from t w              

here id1=:"SYS_B_0"               

 

--生成一个父游标和一个子游标;

SQL> select sql_id, child_number from V$sql where sql_id='bvdkhydtduzb6';

 

SQL_ID        CHILD_NUMBER

------------- ------------

bvdkhydtduzb6            0

 

 

注意,我们输入的SQL是一个条件硬编码的SQLcursor_sharing取值为SIMILAR之后,一个重要特性就是SQL被改写,原有条件列被占用符替换。这样就变化为一个使用绑定变量的SQL语句。

 

下面分别执行两个SQL,除了where条件中id1取值不同之外,字面值相同。

 

--取定2000取值;

SQL> select /*+ demo_id1 */ count(*) from t where id1=2000;

 

  COUNT(*)

----------

         1

 

--取定3000取值;

SQL> select /*+ demo_id1 */ count(*) from t where id1=3000;

 

  COUNT(*)

----------

         1

 

SQL> select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like 'select /*+ demo_id1 */%';

 

SQL_TEXT             SQL_ID        VERSION_COUNT EXECUTIONS

-------------------- ------------- ------------- ----------

select /*+ demo_id1  bvdkhydtduzb6             1          3

*/ count(*) from t w                            

here id1=:"SYS_B_0"                             

 

SQL> select sql_id, child_number, executions from V$sql where sql_id='bvdkhydtduzb6';

 

SQL_ID        CHILD_NUMBER EXECUTIONS

------------- ------------ ----------

bvdkhydtduzb6            0          3

 

 

当我们对id1使用三个不同的取值时,使用的完全是相同的执行计划。SIMILAR的效果和FORCE取值完全相同。Id1列为主键列,取值绝对均匀,是否是由于主键列唯一的特性,让Oracle SIMILAR取值判定是“Safe SQL?

 

我们进行下面的试验,对id2列进行。Id2列为一个唯一索引列,取值和id1列完全相同。看看此时的效果。

 

 

--id2

SQL> select /*+ demo_id2 */ count(*) from t where id2=1000;

 

  COUNT(*)

----------

         1

 

SQL> select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like 'select /*+ demo_id2 */%';

SQL_TEXT             SQL_ID        VERSION_COUNT EXECUTIONS

-------------------- ------------- ------------- ----------

select /*+ demo_id2  1wnrjz4j2dkqr             1          1

*/ count(*) from t w                            

here id2=:"SYS_B_0"                             

 

SQL> select sql_id, child_number, executions from V$sql where sql_id='1wnrjz4j2dkqr';

SQL_ID        CHILD_NUMBER EXECUTIONS

------------- ------------ ----------

1wnrjz4j2dkqr            0          1

 

 

再次尝试20003000id2取值。

 

 

SQL> select /*+ demo_id2 */ count(*) from t where id2=2000;

  COUNT(*)

----------

         1

 

SQL> select /*+ demo_id2 */ count(*) from t where id2=3000;

 

  COUNT(*)

----------

         1

 

SQL> select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like 'select /*+ demo_id2 */%';

SQL_TEXT             SQL_ID        VERSION_COUNT EXECUTIONS

-------------------- ------------- ------------- ----------

select /*+ demo_id2  1wnrjz4j2dkqr             1          3

*/ count(*) from t w                            

here id2=:"SYS_B_0"                             

 

 

SQL> select sql_id, child_number, executions from V$sql where sql_id='1wnrjz4j2dkqr';

 

SQL_ID        CHILD_NUMBER EXECUTIONS

------------- ------------ ----------

1wnrjz4j2dkqr            0          3

 

 

注意,此时传入的SQL语句发生where条件取值替换为绑定变量的现象,但是同时都是针对其对应一个执行计划。难道说,Oracle能“看出”唯一索引的效果?

 

最后进行一般列id3的试验。

 

 

SQL> select /*+ demo_id3 */ count(*) from t where id3=1000;

  COUNT(*)

----------

         1

 

SQL> select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like 'select /*+ demo_id3 */%';

 

SQL_TEXT             SQL_ID        VERSION_COUNT EXECUTIONS

-------------------- ------------- ------------- ----------

select /*+ demo_id3  c0yvrw873f8gw             1          1

*/ count(*) from t w                             

here id3=:"SYS_B_0"                             

 

 

 

SQL> select /*+ demo_id3 */ count(*) from t where id3=2000;

 

  COUNT(*)

----------

         1

 

SQL> select /*+ demo_id3 */ count(*) from t where id3=3000;

 

  COUNT(*)

----------

         1

 

SQL>  select sql_text, sql_id, version_count, executions from v$sqlarea where sql_text like 'select /*+ demo_id3 */%';

 

SQL_TEXT             SQL_ID        VERSION_COUNT EXECUTIONS

-------------------- ------------- ------------- ----------

select /*+ demo_id3  c0yvrw873f8gw             1          3

*/ count(*) from t w                            

here id3=:"SYS_B_0"                             

 

SQL> select sql_id, child_number, executions from V$sql where sql_id='c0yvrw873f8gw';

 

SQL_ID        CHILD_NUMBER EXECUTIONS

------------- ------------ ----------

c0yvrw873f8gw            0          3

 

 

普通数据列id3也只对应一条执行计划。

 

从上面对id1-id3的试验情况看,cursor_sharing=SIMILAROracle是会对SQL字面值中的条件进行绑定变量替换。但是判定“Safe SQL”的标准一定不是数据列描述信息。

 

那么,SIMILARFORCE在判定“Safe SQL”上的差异,是什么标准呢?我们下篇继续探讨。

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-709321/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/17203031/viewspace-709321/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值