Oracle 优化器动态统计(Dynamic Statistics)

Posted SQLplusDB

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle 优化器动态统计(Dynamic Statistics)相关的知识,希望对你有一定的参考价值。

概述

为了解决因为统计信息缺失或者统计不够准确而引起的问题,从9iR2的版本开始Oracle推出了动态采样(Dynamic Sampling)功能,使SQL文在硬解析过程中动态地收集统计信息。
该功能在以后的版本上得到更进一步的增强,从11.2.0.4版本改称为动态统计(Dynamic Statistics 以后简称DS )。

关于动态统计,对于有一些ORACLE数据库从业经验的人员来说,也许并不陌生,因此在阅读本章内容时,我希望大家先回顾以下几个问题,如果某方面有些不足可以重点进行阅读。

关于动态统计(DS )的几个问题:

1.什么是动态统计(Dynamic Statistics)或者动态采样(Dynamic Sampling)?
2.为什么要使用动态统计?
3.动态统计都有哪些级别,各个级别都有什么区别?
4.如何确认采用了动态统计功能?
5.动态统计在各个版本上有什么区别?
6.如何禁用动态统计和12c的自动动态统计?
7.动态统计的利弊,常见问题?

下面章节将针对以上的问题进行解答和说明:

什么是动态统计(Dynamic Statistics)或者动态采样(Dynamic Sampling)?

动态采样是Oracle从9iR2的版本开始推出的一项优化技术,通过执行一些递归SQL(recursive SQL )来随机访问表块,收集一些采样信息,来预估谓词的选择率(selectivities)。

9i以后的版本中不断进行功能加强,在11.2.0.4版本改称为动态统计(Dynamic Statistics)。
在12c版本后进一步推出自动动态统计(Automatic Dynamic Statistics)。

为什么要使用动态统计?

如同前面叙述的,如果由于选择执行计划的Object统计信息缺失、过期或者不足时,CBO优化器选择的执行计划就有可能不是最优的甚至是最差的。

所以为了保证优化器在SQL硬解析时选择到最优的执行计划,根据数据库动态统计的设置级别,进行动态收集Object的统计信息。

动态统计都有哪些级别,各个级别都有什么区别?

数据库动态统计的级别主要通过参数OPTIMIZER_DYNAMIC_SAMPLING的值(同级别)来决定。

关于OPTIMIZER_DYNAMIC_SAMPLING的值(同级别)和动态统计启用的条件可以参考下表:

※其中样本大小的数据块数可以由隐含参数_optimizer_dyn_smp_blks来控制(默认值为32)。

如何确认采用了动态统计功能?

我们可以通过以下的方法来确认一个查询是否使用了动态统计功能:

1.利用DBMS_XPLAN.DISPLAY_CURSOR功能查看是否使用了DS
2.利用Optimizer Trace(10053 Trace)查看是否使用了DS
3.利用SQL Trace(10046 Trace)查看是否使用了DS

我们通过以下的例子,来看一下查看某个查询是否使用动态统计。
(在12.1.0.2版本上进行测试)

---首先我们准备查询用的数据
SQL> conn SH/SH
Connected.
---查看optimizer_dynamic_sampling的级别
SQL> SHOW PARAMETERS optimizer_dynamic_sampling

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_dynamic_sampling           integer     2

---使统计信息缺失,以便采用动态统计
SQL> EXEC DBMS_STATS.DELETE_SCHEMA_STATS('sh');

PL/SQL procedure successfully completed.

---设定Optimizer Trace(10053 Trace)和SQL Trace(10046 Trace)
SQL> alter session set tracefile_identifier='sampling_10053_10046';

Session altered.

SQL> alter session set statistics_level=all;

Session altered.

SQL> alter session set max_dump_file_size = unlimited;

Session altered.

SQL> alter session set events '10046 trace name context forever, level 12';

Session altered.

SQL> ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';

Session altered.

---执行SQL文
SQL> SELECT /* statis sampling1 */
  2         p.prod_name, COUNT(*)
  3    FROM sales s,
  4         products p
  5   WHERE s.time_id >= TO_DATE(' 1997-07-01 00:00:00',
  6      'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
  7     AND s.time_id < TO_DATE(' 1998-04-01 00:00:00',
  8      'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
  9     AND s.prod_id = p.prod_id
 10   GROUP BY
 11         p.prod_name;

PROD_NAME                                            COUNT(*)
-------------------------------------------------- ----------
...
60 rows selected.

---通过dbms_xplan.display_cursor查看执行计划。
SQL> SET PAGES 2000 LIN 300 
SQL> select * from table(dbms_xplan.display_cursor(null,null,'NOTE ALLSTATS LAST'));
SQL_ID  62054vzrc3rcr, child number 0
-------------------------------------
SELECT /* statis sampling1 */        p.prod_name, COUNT(*)   FROM sales
s,        products p  WHERE s.time_id >= TO_DATE(' 1997-07-01
00:00:00',     'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
AND s.time_id < TO_DATE(' 1998-04-01 00:00:00',     'SYYYY-MM-DD
HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')    AND s.prod_id = p.prod_id
GROUP BY        p.prod_name

Plan hash value: 1538978877

----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |                |      1 |        |     60 |00:00:00.64 |    2339 |       |       |          |
|   1 |  HASH GROUP BY                               |                |      1 |  44240 |     60 |00:00:00.64 |    2339 |   974K|   974K| 3016K (0)|
|*  2 |   HASH JOIN                                  |                |      1 |  44240 |  43687 |00:00:00.57 |    2339 |  1185K|  1185K| 1598K (0)|
|   3 |    TABLE ACCESS FULL                         | PRODUCTS       |      1 |     72 |     72 |00:00:00.01 |       4 |       |       |          |
|   4 |    PARTITION RANGE ITERATOR                  |                |      1 |  44240 |  43687 |00:00:00.33 |    2335 |       |       |          |
|   5 |     TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| SALES          |      2 |  44240 |  43687 |00:00:00.21 |    2335 |       |       |          |
|   6 |      BITMAP CONVERSION TO ROWIDS             |                |      1 |        |  43687 |00:00:00.06 |       4 |       |       |          |
|*  7 |       BITMAP INDEX RANGE SCAN                | SALES_TIME_BIX |      1 |        |     90 |00:00:00.01 |       4 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("S"."PROD_ID"="P"."PROD_ID")
   7 - access("S"."TIME_ID">=TO_DATE(' 1997-07-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "S"."TIME_ID"<TO_DATE(' 1998-04-01 00:00:00',
              'syyyy-mm-dd hh24:mi:ss'))

Note
-----
   - dynamic statistics used: dynamic sampling (level=2) ★
   - this is an adaptive plan

dbms_xplan.display_cursor

我们可以看到,通过dbms_xplan.display_cursor输出的执行计划有如下的Note内容:
采用了级别为2的动态统计。

Note
-----
   - dynamic statistics used: dynamic sampling (level=2) 

10053

然后我们再看一看Optimizer Trace(10053 Trace)中关于动态统计的部分输出,并有包含/* OPT_DYN_SAMP */ 提示的递归调用SQL文:
(详细记录了动态采样的过程)

*** 2016-05-18 20:48:36.534
** Performing dynamic sampling initial checks. **★
  Column (#3): TIME_ID(DATE)  Part#: 3  NO STATISTICS (using defaults)
    AvgLen: 9 NDV: 250 Nulls: 0 Density: 0.003998
  Column (#3): TIME_ID(DATE)  Part#: 4  NO STATISTICS (using defaults)
    AvgLen: 9 NDV: 250 Nulls: 0 Density: 0.003998
  Column (#3): TIME_ID(DATE)  NO STATISTICS (using defaults)
    AvgLen: 9 NDV: 250 Nulls: 0 Density: 0.004000
** Dynamic sampling initial checks returning TRUE (level = 2).★
** Dynamic sampling updated index stats.: SALES_CHANNEL_BIX, blocks=119
** Dynamic sampling updated index stats.: SALES_CUST_BIX, blocks=574
** Dynamic sampling updated index stats.: SALES_PROD_BIX, blocks=105
** Dynamic sampling updated index stats.: SALES_PROMO_BIX, blocks=87
** Dynamic sampling updated index stats.: SALES_TIME_BIX, blocks=127
** Dynamic sampling index access candidate : SALES_TIME_BIX
** Dynamic sampling updated table stats.: blocks=97

*** 2016-05-18 20:48:36.534
** Generated dynamic sampling query: ★
    query text : 
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE 
... 
*** 2016-05-18 20:48:36.695
** Executed dynamic sampling query:★
    level : 2
    sample pct. : 63.917526
    total partitions : 28
      partitions for sampling : 2
      partitioning pct. : 7.142857
    actual sample size : 28277
    filtered sample card. : 28277
    orig. card. : 8005
    block cnt. table stat. : 97
    block cnt. for sampling: 97
    max. sample block cnt. : 64
    sample block cnt. : 62
    ndv C3 : 57
        scaled : 57.00
    nulls C4 : 0
        scaled : 0.00
    min. sel. est. : 0.00250000
** Dynamic sampling col. stats.:
  Column (#1): PROD_ID(NUMBER)  Part#: 0
    AvgLen: 22 NDV: 57 Nulls: 0 Density: 0.017544
** Using dynamic sampling NULLs estimates.
** Using dynamic sampling NDV estimates.
   Scaled NDVs using cardinality = 619358.

10046

我们可以通过查看SQL Trace(10046 Trace)中的一些以SELECT /* OPT_DYN_SAMP */… 开头的动态采样递归SQL来判断是否采用了动态统计功能。

例如:
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE 
  NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') 
  NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_00"), 
  NVL(SUM(C2),:"SYS_B_01"), COUNT(DISTINCT C3), NVL(SUM(CASE WHEN C3 IS NULL 
  THEN :"SYS_B_02" ELSE :"SYS_B_03" END),:"SYS_B_04") 
FROM
 (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("S") FULL("S") 
  NO_PARALLEL_INDEX("S") */ :"SYS_B_05" AS C1, CASE WHEN "S"."TIME_ID">=
  TO_DATE(:"SYS_B_06", :"SYS_B_07") AND "S"."TIME_ID"<TO_DATE(:"SYS_B_08", 
  :"SYS_B_09") THEN :"SYS_B_10" ELSE :"SYS_B_11" END AS C2, "S"."PROD_ID" AS 
  C3 FROM "SH"."SALES" SAMPLE BLOCK (:"SYS_B_12" , :"SYS_B_13") SEED 
  (:"SYS_B_14") "S" WHERE "S"."TIME_ID">=TO_DATE(:"SYS_B_15", :"SYS_B_16") 
  AND "S"."TIME_ID"<TO_DATE(:"SYS_B_17", :"SYS_B_18")) SAMPLESUB

版权声明:本文为博主原创文章,转载必须注明出处,本人保留一切相关权力!http://blog.csdn.net/lukeunique

动态统计在各个版本上有什么区别?

下面我们再介绍一下在各个版本上,动态统计有什么特点和那些比较大的演进:

9iR2

在9iR2的版本上推出,称为动态采样(Dynamic Sampling)。

DB 11.2.0.1

在11.2.0.1 的版本上,推出了自动调整(AUTO-ADJUST)功能。
即,11.2.0.1以后的版本,如果动态采样采用的级别是默认级别2,Oracle就有可能根据查询语句的特点自动调整(AUTO-ADJUST)动态采样的级别;调整后的级别范围为4~8.
当然根据需要,你也可以下面的语句关闭这项功能。

SQL> alter session set "_fix_control" = '7452863:off'; 

DB 11.2.0.4

在11.2.0.4 的版本上,推出了一个新的级别11,并且正式改名为动态统计(Dynamic Statistics)
即,如果把级别设为11,将由Oracle优化器自行决定动态采样范围和采样大小。

12c

在12c的版本上,推出了自动动态统计(Automatic Dynamic Statistics)功能。
即,当满足下面任何的一个条件时,Oracle优化器自行决定动态采样范围和采样大小。

  ・级别为默认级别2时 或者 级别设为11
  ・指定SQL HINT(dynamic_sampling)启用动态统计
  ・并行查询
  ・执行过的查询语句并且其执行履历还是可用的(如在内存中,AWR中等)。

当然还有由于如自适应执行计划,统计反馈,SQL计划指令等自适应查询优化(Adaptive Query Optimization)触发的一些情况。

※可以通过以下设定,使并行查询时的12c自动动态统计无效。

    SQL> alter system set "_fix_control"= '12914055:off'

如何禁用动态统计和12c的自动动态统计?

你可以通过如下几种方法禁用动态统计:

OPTIMIZER_DYNAMIC_SAMPLING

你可以通过设置初始化参数OPTIMIZER_DYNAMIC_SAMPLING为0可以彻底地使动态统计功能无效。

例:

SQL> conn /as sysdba
Connected.
SQL>---系统级别    
SQL> show parameter OPTIMIZER_DYNAMIC_SAMPLING

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_dynamic_sampling           integer     2
SQL> alter system set optimizer_dynamic_sampling=0;

System altered.

SQL> show parameter OPTIMIZER_DYNAMIC_SAMPLING

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_dynamic_sampling           integer     0

--会话级别
SQL> alter session set optimizer_dynamic_sampling=0;

Session altered.

SQL> show parameter OPTIMIZER_DYNAMIC_SAMPLING

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_dynamic_sampling           integer     0

HINT

可以通过dynamic_sampling HINT,针对某些特定SQL使动态统计无效。

select /*+ dynamic_sampling(0) */ ...

也可以通过dynamic_sampling HINT,针对某些特定语句中的特定表,使动态统计无效。

SELECT /*+ dynamic_sampling(<tab/alias name> 0) */

关于12c版本上的自动动态统计

在12c版本上,自动动态统计(ADS)属于自动查询优化(Adaptive query optimization)的一部分,所以通过参数OPTIMIZER_ADAPTIVE_FEATURES也可以对自动动态统计(ADS)进行控制。
但是需要明确的是,参数OPTIMIZER_ADAPTIVE_FEATURES仅仅能控制12c ADS的使用,并不能控制默认的动态统计功能。即:

  当OPTIMIZER_ADAPTIVE_FEATURES = TRUE 并且OPTIMIZER_DYNAMIC_SAMPLING = 2 时,自动动态统计(ADS)有效。

  当OPTIMIZER_ADAPTIVE_FEATURES = FALSE 并且OPTIMIZER_DYNAMIC_SAMPLING = 2 时,自动动态统计(ADS)无效,但是默认的动态统计(Level 2)依然会有效。

  另外,当OPTIMIZER_DYNAMIC_SAMPLING = 11时,无论OPTIMIZER_ADAPTIVE_FEATURES的值是TRUE 和FALSE ,12c ADS都会有效。

在12c版本上的自动动态统计有效的情况下,动态收集的统计信息还会保存在内存的结果缓存(Result Cache)中,以便供其他相关的查询使用。
我们可以通过 参数_optimizer_ads_use_result_cache来控制是否保存统计结果到结果缓存(Result Cache)中。

动态统计的利弊?

我们知道任何新功能都是一把双刃剑,有优点也有缺点,对于动态统计也一样。
动态统计最大的优点是,在优化器选择执行计划时,对统计信息缺失或者统计不够准确的对象,能够动态地收集统计信息,从而获得相对好的执行计划。
并且在12c中优化器还能够自行决定统计收集级别和在内存中保存统计结果,供其他操作共享。
而其也有着缺点,就是使硬解析时候的解析时间可能变得更长,而且如果大量的动态收集操作发生时可能影响到数据库全体性能。

版权声明:本文为博主原创文章,转载必须注明出处,本人保留一切相关权力!http://blog.csdn.net/lukeunique

欢迎关注技术文章首发平台微信订阅号:TeacherWhat

参考

Database SQL Tuning Guide
https://docs.oracle.com/database/121/TGSQL/tgsql_statscon.htm#TGSQL341

Dynamic Statistics

https://blogs.oracle.com/optimizer/entry/dynamic_sampling_and_its_impact_on_the_optimizer

Dynamic sampling and its impact on the Optimizer

https://docs.oracle.com/database/121/TGSQL/tgsql_astat.htm#GUID-DEE2AF8B-5F4B-4FE7-9F0E-7D188921EBCC

About Dynamic Statistics Levels

以上是关于Oracle 优化器动态统计(Dynamic Statistics)的主要内容,如果未能解决你的问题,请参考以下文章

动态采样---DYNAMIC_SAMPLING 基于tom文章的翻译

Oracle动态采样学习

Oracle动态采样学习

ORACLE动态采样

ORACLE 收集统计信息

oracle统计信息