Oracle自适应共享游标——Adaptive Cursor Sharing(下)

 

 

自适应游标共享是Oracle11g推出的一个新特性。通过ACS,我们可以一定程度上缓解由于bind peeking和cursor_sharing参数设置带来的子游标共享问题。在前篇(http://space.itpub.net/17203031/viewspace-703280)中,我们已经观察过Oracle 10g下的bind peeking和游标共享,以及11g上的ACS特性。本篇,我们打算深入分析一下与ACS有关的视图和参数,最后综述一下ACS的优劣。

 

1、 ACS相关参数和视图对象

 

Oracle ACS是有相应的技术背景的。在CBO环境下,ACS是解决bind peeking对bad SQL statement解析的一种方式。所以,存在相关系统参数与ACS对应。

 

ü        optimizer_mode:优化器模式,表示选择使用CBO还是RBO。在目前使用的10g和11g中,由于dynamic sampling技术的存在,大部分情况下,我们是在CBO优化模式下。通常使用choose就可以了;

ü        optimizer_features_enable:使用优化器特性版本。启用ACS使用11.2.0.1即可;

ü        optimizer_capture_sql_plan_baselines=false:关闭SQL 执行计划baseline管理机制;

ü        cursor_sharing=EXACT:完全匹配的绑定变量机制;

ü        _optim_peek_user_binds:是否开启绑定变量机制;

 

之后的三个参数与ACS开启与否相关:

 

ü        _optimizer_adaptive_cursor_sharing=TRUE:

ü        _optimizer_extended_cursor_sharing=UDO;

ü        _optimizer_extended_cursor_sharing_rel=SIMPLE;

 

除了这些与ACS相关的参数,还新增加了三个度量视图用于ACS的正常工作。

 

ü        v$sql_cs_histogram:Oracle 11g使用分配的频率确定SQL是否是bind sensitive。其中包括执行次数和落在查询上的游标个数;

ü        v$sql_cs_selectitiy:包括有关SQL语句谓词的相对选择性信息。也就是选择率立方体;

ü        v$sql_cs_statistics:列出自适应游标是否被共享以及如何共享统计量信息;

 

 

通过这些新增加的参数和度量视图,Oracle实现了ACS的自适应过程。

 

2、 自适应游标过程

 

下面我们进行试验,来观察对ACS的测算机制。注意:我们采用前篇相同的数据表和分布情况。

 

 

SQL> select * from v$version;

 

BANNER

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

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE    11.2.0.1.0    Production

 

SQL> select dbms_stats.get_param('method_opt') from dual;

DBMS_STATS.GET_PARAM('METHOD_O

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

FOR ALL COLUMNS SIZE AUTO

 

 

对数据表收集统计信息之后,频度直方图在id1列出现。说明统计量中已经包括了直方图信息。

 

 

 

SQL> select id1, count(*) from t group by id1;

 

ID1          COUNT(*)

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

U                  20

K               10000

M                  20

O               30000

 

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

 

TABLE_NAME                     COLUMN_NAME                    HISTOGRAM

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

T                              ID1                            FREQUENCY

T                              ID2                            NONE

T                              ID3                            NONE

 

 

取值原因,id1列的直方图只有4个bucket。

 

 

SQL> select ENDPOINT_NUMBER, ENDPOINT_VALUE, ENDPOINT_ACTUAL_VALUE from dba_tab_histograms where table_name='T' and wner='SYS' and column_name='ID1';

 

ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALUE

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

           1407 3.894222643901

           1414 3.998068581071

           5594 4.101914518242

           5596 4.413452329754

 

 

 

ü        第一次绑定变量测试

 

id1=O,筛选数据行30000行,应该走全表扫描路径。

 

 

SQL> var i varchar2(10);

SQL> exec :i:='O';

 

PL/SQL 过程已成功完成。

 

已用时间:  00: 00: 00.01

SQL> select * from t where id1=:i;

 

已选择30000行。

 

 

此时父子游标状况为。生成了一个父游标和第一个子游标。生成执行计划过程中使用了bind peeking技术。

 

 

SQL> select sql_text, SQL_ID,  VERSION_COUNT, VERSION_COUNT, executions, IS_BIND_SENSITIVE,  IS_BIND_AWARE from v$sqlarea where sql_text like 'select * from t where id1=:i%';

 

SQL_TEXT                       SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i   a3y1yrq36v0gn             1             1          1 Y                 N

 

 

SQL> select sql_text, CHILD_NUMBER, IS_BIND_SENSITIVE, IS_BIND_AWARE, IS_SHAREABLE from v$sql where sql_id='a3y1yrq36v0gn';

 

SQL_TEXT                       CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE

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

select * from t where id1=:i              0 Y                 N             Y

 

 

各列含义在前篇中已经陈述,不加以累述了。此时的执行计划如下:

 

 

SQL> select * from table(dbms_xplan.display_cursor('a3y1yrq36v0gn',0,format => 'advanced'));

 

PLAN_TABLE_OUTPUT

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

SQL_ID  a3y1yrq36v0gn, child number 0

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

select * from t where id1=:i

Plan hash value: 1601196873

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | SELECT STATEMENT  |      |       |       |    19 (100)|          |

|*  1 |  TABLE ACCESS FULL| T    | 29908 |   175K|    19   (0)| 00:00:01 |

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

Peeked Binds (identified by position):

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

   1 - :I (VARCHAR2(30), CSID=873): 'O'

Predicate Information (identified by operation id):

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

   1 - filter("ID1"=:I)

 

48 rows selected

 

 

使用了绑定变量O,采用了全表扫描执行计划。三个CS视图如下:

 

 

SQL> select * from v$sql_cs_histogram where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER  BUCKET_ID      COUNT

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

433F59CC 2255323636 a3y1yrq36v0gn            0          0          0

433F59CC 2255323636 a3y1yrq36v0gn            0          1          1

433F59CC 2255323636 a3y1yrq36v0gn            0          2          0

 

SQL> select * from v$sql_cs_selectivity where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER PREDICATE                                  RANGE_ID LOW        HIGH

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

 

SQL> select * from v$sql_cs_statistics where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER BIND_SET_HASH_VALUE PEEKED EXECUTIONS ROWS_PROCESSED BUFFER_GETS   CPU_TIME

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

433F59CC 2255323636 a3y1yrq36v0gn            0          3804331937 Y               1          30000        2094          0

 

 

第一次执行生成了编号为0的子游标,执行值对应落在bucket_id=1的计数上。

 

ü        第二次绑定变量测试

 

第二次选择一个索引执行计划。

 

 

SQL> exec :i:='U';

PL/SQL 过程已成功完成。

 

已用时间:  00: 00: 00.02

SQL> select * from t where id1=:i;

 

已选择20行。

 

 

对应执行计划信息:

 

 

SQL> select sql_text, SQL_ID, VERSION_COUNT, VERSION_COUNT, executions, IS_BIND_SENSITIVE, IS_BIND_AWARE from v$sqlarea where sql_text like 'select * from t where id1=:i%';

 

SQL_TEXT                       SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i   a3y1yrq36v0gn             1             1          2 Y                 N

 

 

SQL> select sql_text, CHILD_NUMBER, IS_BIND_SENSITIVE, IS_BIND_AWARE, IS_SHAREABLE, executions from v$sql where sql_id='a3y1yrq36v0gn';

 

SQL_TEXT                       CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE EXECUTIONS

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

select * from t where id1=:i              0 Y                 N             Y                     2

 

 

注意!虽然这个执行显然是走索引计划比较好,但是Oracle并没有为它生成索引执行计划。统计量如下:

 

 

SQL>  select * from v$sql_cs_histogram where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER  BUCKET_ID      COUNT

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

433F59CC 2255323636 a3y1yrq36v0gn            0          0          1

433F59CC 2255323636 a3y1yrq36v0gn            0          1          1

433F59CC 2255323636 a3y1yrq36v0gn            0          2          0

 

SQL> select * from v$sql_cs_selectivity where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER PREDICATE                                  RANGE_ID LOW        HIGH

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

 

SQL> select * from v$sql_cs_statistics where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER BIND_SET_HASH_VALUE PEEKED EXECUTIONS ROWS_PROCESSED BUFFER_GETS   CPU_TIME

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

433F59CC 2255323636 a3y1yrq36v0gn            0          3804331937 Y               1          30000        2094          0

 

 

第二次执行就落入了第一个bucket中。

 

ü        第三次绑定变量实验

 

此时,我们再次使用U作为绑定变量取值进行调用。

 

 

SQL> select * from t where id1=:i;

已选择20行。

 

已用时间:  00: 00: 00.03

 

 

此时,出现新的子游标对应。

 

 

SQL>  select sql_text, SQL_ID, VERSION_COUNT, VERSION_COUNT, executions, IS_BIND_SENSITIVE, IS_BIND_AWARE from v$sqlarea where sql_text like 'select * from t where id1=:i%';

 

SQL_TEXT                       SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i   a3y1yrq36v0gn             2             2          3 Y                 Y

 

SQL>  select sql_text, CHILD_NUMBER, IS_BIND_SENSITIVE, IS_BIND_AWARE, IS_SHAREABLE, executions from v$sql where sql_id='a3y1yrq36v0gn';

 

SQL_TEXT                       CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE EXECUTIONS

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

select * from t where id1=:i              0 Y                 N             Y                     2

select * from t where id1=:i              1 Y                 Y             Y                     1

 

 

这个时候,命中统计量出现变化。

 

 

SQL> select * from v$sql_cs_histogram where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER  BUCKET_ID      COUNT

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

433F59CC 2255323636 a3y1yrq36v0gn            1          0          1

433F59CC 2255323636 a3y1yrq36v0gn            1          1          0

433F59CC 2255323636 a3y1yrq36v0gn            1          2          0

433F59CC 2255323636 a3y1yrq36v0gn            0          0          1

433F59CC 2255323636 a3y1yrq36v0gn            0          1          1

433F59CC 2255323636 a3y1yrq36v0gn            0          2          0

 

6 rows selected

 

SQL> select * from v$sql_cs_selectivity where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER PREDICATE                                  RANGE_ID LOW        HIGH

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

433F59CC 2255323636 a3y1yrq36v0gn            1 =I                                                0 0.000241   0.000295

 

SQL> select * from v$sql_cs_statistics where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER BIND_SET_HASH_VALUE PEEKED EXECUTIONS ROWS_PROCESSED BUFFER_GETS   CPU_TIME

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

433F59CC 2255323636 a3y1yrq36v0gn            1          1852677911 Y               1             40           7          0

433F59CC 2255323636 a3y1yrq36v0gn            0          3804331937 Y               1          30000        2094          0

 

 

对新生成的游标。Oracle将刚才的命中率放在第一个直方图下。并且归纳该新游标对应的统计量分布数量。

 

此时,执行计划为:

 

 

SQL> select * from table(dbms_xplan.display_cursor('a3y1yrq36v0gn',1,format => 'advanced'));

 

PLAN_TABLE_OUTPUT

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

SQL_ID  a3y1yrq36v0gn, child number 1

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

select * from t where id1=:i

Plan hash value: 2247614985

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

| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| T

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

|   0 | SELECT STATEMENT            |           |       |       |     2 (100)|

|   1 |  TABLE ACCESS BY INDEX ROWID| T         |    11 |    66 |     2   (0)| 0

|*  2 |   INDEX RANGE SCAN          | IDX_T_ID1 |    11 |       |     1   (0)| 0

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

Peeked Binds (identified by position):

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

   1 - :I (VARCHAR2(30), CSID=873): 'U'

 

50 rows selected

 

 

ü        第四次执行绑定变量

 

此时,我们还是选择U作为执行的绑定变量取值。

 

 

SQL> select * from t where id1=:i;

已选择20行。

 

SQL>  select sql_text, SQL_ID, VERSION_COUNT, VERSION_COUNT, executions, IS_BIND_SENSITIVE,  IS_BIND_AWARE from v$sqlarea where sql_text like 'select * from t where id1=:i%';

 

SQL_TEXT                                                                         SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i                                                     a3y1yrq36v0gn             2             2          4 Y                 Y

 

SQL> col sql_text for a30;

SQL>  select sql_text, SQL_ID, VERSION_COUNT,VERSION_COUNT,executions,IS_BIND_SENSITIVE, IS_BIND_AWARE from v$sqlarea where sql_text like 'select * from t where id1=:i%';

 

SQL_TEXT                       SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i   a3y1yrq36v0gn             2             2          4 Y                 Y

 

SQL> select sql_text, CHILD_NUMBER, IS_BIND_SENSITIVE, IS_BIND_AWARE, IS_SHAREABLE, executions from v$sql where sql_id='a3y1yrq36v0gn';

 

SQL_TEXT                       CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE EXECUTIONS

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

select * from t where id1=:i              0 Y                 N             Y                     2

select * from t where id1=:i              1 Y                 Y             Y                     2

 

SQL>  select * from v$sql_cs_histogram where sql_id='a3y1yrq36v0gn';

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER  BUCKET_ID      COUNT

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

433F59CC 2255323636 a3y1yrq36v0gn            1          0          2

433F59CC 2255323636 a3y1yrq36v0gn            1          1          0

433F59CC 2255323636 a3y1yrq36v0gn            1          2          0

433F59CC 2255323636 a3y1yrq36v0gn            0          0          1

433F59CC 2255323636 a3y1yrq36v0gn            0          1          1

433F59CC 2255323636 a3y1yrq36v0gn            0          2          0

 

6 rows selected

 

 

相同命中子游标child_number=2。

 

ü        第五次绑定变量执行

 

当执行一次同分布数据值的时候。

 

 

SQL> exec :i:='M';

PL/SQL 过程已成功完成。

 

已用时间:  00: 00: 00.02

SQL> select * from t where id1=:i;

 

已选择20行。

 

 

此时,生成了一个新的游标。进行索引计划的调用。

 

 

SQL>

 

SQL_TEXT                       SQL_ID        VERSION_COUNT VERSION_COUNT EXECUTIONS IS_BIND_SENSITIVE IS_BIND_AWARE

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

select * from t where id1=:i   a3y1yrq36v0gn             3             3          5 Y                 Y

 

SQL_TEXT                       CHILD_NUMBER IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE EXECUTIONS

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

select * from t where id1=:i              0 Y                 N             Y                     2

select * from t where id1=:i              1 Y                 Y             N                     2

select * from t where id1=:i              2 Y                 Y             Y                     1

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER  BUCKET_ID      COUNT

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

433F59CC 2255323636 a3y1yrq36v0gn            2          0          1

433F59CC 2255323636 a3y1yrq36v0gn            2          1          0

433F59CC 2255323636 a3y1yrq36v0gn            2          2          0

433F59CC 2255323636 a3y1yrq36v0gn            1          0          2

433F59CC 2255323636 a3y1yrq36v0gn            1          1          0

433F59CC 2255323636 a3y1yrq36v0gn            1          2          0

433F59CC 2255323636 a3y1yrq36v0gn            0          0          1

433F59CC 2255323636 a3y1yrq36v0gn            0          1          1

433F59CC 2255323636 a3y1yrq36v0gn            0          2          0

 

9 rows selected

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER PREDICATE                                  RANGE_ID LOW        HIGH

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

433F59CC 2255323636 a3y1yrq36v0gn            2 =I                                                0 0.000241   0.001376

433F59CC 2255323636 a3y1yrq36v0gn            1 =I                                                0 0.000241   0.000295

 

ADDRESS  HASH_VALUE SQL_ID        CHILD_NUMBER BIND_SET_HASH_VALUE PEEKED EXECUTIONS ROWS_PROCESSED BUFFER_GETS   CPU_TIME

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

433F59CC 2255323636 a3y1yrq36v0gn            2          1492060625 Y               1             40           7          0

433F59CC 2255323636 a3y1yrq36v0gn            1          1852677911 Y               1             40           7          0

433F59CC 2255323636 a3y1yrq36v0gn            0          3804331937 Y               1          30000        2094          0

 

 

同时子游标1也失去了被共享的能力。

 

3、ACS的优劣

 

通过上面的实验,我们观察到了基于直方图和成本不断试算的ACS工作过程。ACS的引入,带来了下面几个好处:

 

ü        缓解bind peeking带来的性能问题

 

oracle 11g之前,使用绑定变量的时候难免出现bind peeking副作用。也就是对于一些bad SQL游标执行计划过度共享,而且性能不稳定的现象。即使通过调整cursor_sharing,非绑定变量语句也会或者生成过多的子游标、或者同样进入bind peeking过度共享。使用ACS后,可以自动的对bind peeking问题进行一系列的补救方式,以其生成适合的执行计划配比。

 

ü        综合化最优性能

 

使用ACS的最理想情况,就是Oracle对每一个使用绑定变量的父游标生成多个适当的子游标执行计划。当输入不同的绑定变量值时,Oracle依据查看的结果,“匹配”到合适的执行计划中。这样,既没有消耗过多的library cache空间,又有匹配的SQl执行计划对应。

 

 

同样,世上没有万灵药,任何事物都有其劣势的一面。ACS也一样。

 

ü        消耗更多的CPU和空间资源

 

进行ACS,Oracle意味着需要消耗更多的CPU进行成本配比试算和评估。同时,生成过多个执行计划也意味着消耗内存library cache资源;

 

ü        自适应过程也会走弯路

 

自适应过程是一个事后实验调节的过程。依据统计量和成本值,Oracle要出现若干次错误执行计划的情况。

 

 

4、 结论

 

作为oracle 11g推出的新特性,ACS一定程度上缓解了bind peeking,特别是生产环境下的,所带来的问题。笔者认为,虽然不能强调是一个万能的方案,但是一个试图解决问题的有益尝试。

 

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

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值