cursor_sharing=similar 与 直方图

Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE 很多MOS文档和书籍都描述,cursor_sharing=similar时,如果谓词列上直方图,那么ORACLE将认为是unsafe的,从而重新硬解析SQL语句,但今天遇到1个问题,发现其和直方图无必然关系,而是和谓词列上是否有统计信息直接相关

 

测试1:使用method_opt => 'for all columns size 1'收集了统计信息

 

SQL> @traceon 10046 12 fl2  

 

[MESSAGE] EVENT:10046  LEVEL:12

[MESSAGE] GREP:fl2  TRACEFILE:/oracle10/admin/SOURCE10/udump/source10_ora_15709.trc

 

SQL> SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>&a;

Enter value for a: 1

old   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>1

  oacflg=10 fl2=0300 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     16923

 

1 row selected.

 

SQL> /

Enter value for a: 2

old   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>2

  oacflg=10 fl2=0300 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     15384

 

1 row selected.

 

SQL> /

Enter value for a: 3

old   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>3

  oacflg=10 fl2=0300 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     13845

 

1 row selected.

 

SQL> /

Enter value for a: 4

old   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq2 */COUNT(*) FROM test WHERE ID>4

  oacflg=10 fl2=0300 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     12306

 

1 row selected.

 

SQL> SELECT parse_calls,executions,loads,version_count FROM v$sqlstats WHERE sql_text LIKE '%zq2%'

  2  ;

 

PARSE_CALLS EXECUTIONS      LOADS VERSION_COUNT

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

          4          4          4             4

 

SQL> SELECT sql_id,plan_hash_value FROM v$sql WHERE sql_text LIKE '%zq2%';

 

SQL_ID        PLAN_HASH_VALUE

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

fph8hajpxnj20      3508397080

fph8hajpxnj20      3508397080

fph8hajpxnj20      3508397080

fph8hajpxnj20      3508397080

 

可以看到,SQL执行了4次,解析了4次,VERSION_COUNT4

游标不能重用的原因为:0x0300,按照MOS文档

       High Version Count with CURSOR_SHARING = SIMILAR or FORCE [ID 261020.1]

        if the field named oacflg2 or flg2 has a value 300 this means the literal was replaces (100) and the literal is unsafe (200).

       

ORACLE认为这种绑定是不安全的(unsafe),导致绑定失败,使得本来应该共享的游标没有共享,从而导致硬解析

       Unsafe Literals or Peeked Bind Variables [ID 377847.1]

        Note that, prior to 11g, unsafe literals are NOT covered by 'bind mismatch' in V$SQL_SHARED_CURSOR  as this is for user bind metadata mismatches.

 

因为cursor_sharing=similarSQL的字面值在替换后相同,其是1个父游标(对应替换后的SQL语句),下带N个子游标(对应subheap 0

这里4次执行的执行计划是相同的,硬解析是完全没有必要的

 

一般来说,在cursor_sharing=similar时,当查询相关的列在存在直方图的情况下,并且运算条件非“=”的情况下,ORACLE会认为是unsafe的。

目前的情况是,已经未收集直方图,DBA_HISTOGRAMS中的2条记录是在收集列统计信息的情况下的最小值(2条数据,一条代表min value,一条代表max value

 

测试2:使用DBMS_STATS.DELETE_COLUMN_STATS(NULL,'TEST','id')删除列的统计信息

 

SQL> @traceon 10046 12 fl2

 

[MESSAGE] EVENT:10046  LEVEL:12

[MESSAGE] GREP:fl2  TRACEFILE:/oracle10/admin/SOURCE10/udump/source10_ora_16394.trc

 

SQL> SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>&a;

Enter value for a: 1

old   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>1

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     16923

 

1 row selected.

 

SQL> /

Enter value for a: 2

old   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>2

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     15384

 

1 row selected.

 

SQL> /

Enter value for a: 3

old   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>3

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     13845

 

1 row selected.

 

SQL> /

Enter value for a: 4

old   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq4 */COUNT(*) FROM test WHERE ID>4

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     12306

 

SQL> SELECT column_name,endpoint_number,endpoint_value

  2    FROM DBA_HISTOGRAMS

  3   WHERE TABLE_NAME = 'TEST'

  4     AND WNER = 'SYS'

  5   ORDER BY 2, 3;

 

COLUMN_NAME                    ENDPOINT_NUMBER ENDPOINT_VALUE

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

NAME                                         0     5.0563E+35

NAME                                         1     5.0563E+35

 

SQL> SELECT parse_calls,executions,loads,version_count FROM v$sqlstats WHERE sql_text LIKE '%zq4%';

 

PARSE_CALLS EXECUTIONS      LOADS VERSION_COUNT

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

          4          4          1             1

 

 

SQL> SELECT sql_id,plan_hash_value FROM v$sql WHERE sql_text LIKE '%zq4%';

 

SQL_ID        PLAN_HASH_VALUE

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

97dm6rb1bf8ah      2901380809

 

可以看到,当删除了ID列统计信息,以彻底删除ID列的直方图后,SQL能如期望中的共享游标

 

根据MOS文档

        QUERIES HAVING HUGE VERSION COUNTS WHEN CURSOR_SHARING=SIMILAR [ID 731468.1]

        Note that the usual reason for seeing high version counts with CURSOR_SHARING=SIMILAR is that there is histogram data on some column/s involved in predicates where the value of the

replaced literal in the predicate varies a lot (eg: on a primary key columns).

        In this case we only share the cursor if the values are identical.

        Be sure to avoid histogram data on such columns.

 

       Unsafe Literals or Peeked Bind Variables [ID 377847.1]

        With CURSOR_SHARING=SIMILAR whenever the optimizer looks at a replaced bind value to make a decision then that bind is checked to see if it should be considered unsafe. The check made is :

    Is the operator NEITHER of   '=' or '!='

    OR

    Are there Column Histograms present on the column.

        If either of these are true then the bind is deemed to be unsafe and a new cursor will be created (So binds used in non equality predicates (eg >, =, <=, LIKE) are unsafe).

 

这里的描述具有迷惑性,直方图信息的来源是sys.histgrm$min/max value的来源为sys.Hist_Head$,这2张表都是DBA_HISTOGRAMS的基表,按照描述理解,删除直方图信息(sys.histgrm$)后,SQL就应该认为是safe的,应该共享游标,而实际情况下,其参考的是sys.Hist_Head$中的数据(sys.Hist_Head$dba_tab_cols的基表),也就是列统计数据。

 

测试3:重新收集统计信息,包括直方图,然后清除sys.Hist_Head$中的列统计

收集直方图,手工删除sys.Hist_Head$中的数据(列统计)(非客户测试环境)

        dbms_stats.gather_table_stats(NULL,'TEST',method_opt => 'for all columns',cascade => TRUE);

        DELETE sys.Hist_Head$ WHERE obj#=14023

 

SQL> @traceon 10046 12 fl2

 

[MESSAGE] EVENT:10046  LEVEL:12

[MESSAGE] GREP:fl2  TRACEFILE:/oracle10/admin/SOURCE10/udump/source10_ora_16835.trc

 

SQL> SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>&a;

Enter value for a: 1

old   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>1

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     16923

 

1 row selected.

 

SQL> /

Enter value for a: 2

old   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>2

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     15384

 

1 row selected.

 

SQL> /

Enter value for a: 3

old   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>3

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     13845

 

1 row selected.

 

SQL> /

Enter value for a: 4

old   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>&a

new   1: SELECT /*+zq6 */COUNT(*) FROM test WHERE ID>4

  oacflg=10 fl2=0100 frm=00 csi=00 siz=24 ff=0

 

  COUNT(*)

----------

     12306

 

1 row selected.

 

SQL> SELECT column_name,endpoint_number,endpoint_value

  2    FROM DBA_HISTOGRAMS

  3   WHERE TABLE_NAME = 'TEST'

  4     AND WNER = 'SYS'

  5     AND column_name='ID'

  6   ORDER BY 2, 3;

 

COLUMN_NAME                    ENDPOINT_NUMBER ENDPOINT_VALUE

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

ID                                        1538              0

ID                                        3077              1

ID                                        4616              2

ID                                        6155              3

ID                                        7694              4

ID                                        9233              5

ID                                       10772              6

ID                                       12310              7

ID                                       13848              8

ID                                       15386              9

ID                                       16924             10

 

COLUMN_NAME                    ENDPOINT_NUMBER ENDPOINT_VALUE

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

ID                                       18462             11

ID                                       20000             12

 

SQL> SELECT A.LOW_VALUE, A.HIGH_VALUE, A.AVG_COL_LEN, A.HISTOGRAM

  2    FROM DBA_TAB_COLUMNS A

  3   WHERE TABLE_NAME = 'TEST'

  4     AND WNER = 'SYS';

 

LOW_VALUE            HIGH_VALUE           AVG_COL_LEN HISTOGRAM

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

                                                      NONE

                                                      NONE

 

是否认为SQL的变量是unsafe的,很大一部分是参考列统计

 

ORACLE未提供不收集列统计信息的子句,只有method_opt选项,可以明确指定一个在查询谓词中不会使用的列给他分析,避免其对其他列生成列统计信息,但是,列统计信息(如density)是CBO成本计算的重要来源,缺失列的统计可能导致执行计划突变

 

还可以修改cursor_sharing = force,但force可能导致一些原来值倾斜的列执行计划不正常,修改前应该先检查SQL的子游标的执行计划是否相同:

select hash_value,plan_hash_value,count(*) from v$sql

where sql_text like '%:"SYS_B_0"%'

group by hash_value,plan_hash_value;

如果全部相同,才能修改。

 

如果部分不同,可以修改后,对这些特定的SQL使用cursor_sharing_exact 提示或者opt_param提示

 

cursor_sharing = similar将在12G被废除

   ANNOUNCEMENT: Deprecating the cursor_sharing = ‘SIMILAR’ setting [ID 1169017.1]

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

转载于:http://blog.itpub.net/8242091/viewspace-676570/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值