关于动态抽样(Dynamic Sampling)

原文:http://www.oracle.com/technetwork/issue-archive/2009/09-jan/o19asktom-086775.html

本文将回答:什么是动态抽样?动态抽样有啥作用?以及不同级别的动态抽样的意思?





1、什么是动态采样?

动态抽样从 oracle 9i第2版引入。它使得优化器(CBO)在硬解析期间有能力抽样一个未分析的表

(any table that has been created and loaded but not yet analyzed)的统计(决定表默认统计),并且可以验证优化器的”猜想“。

因其只在查询硬解析期间为优化器动态生成更好的统计,得名动态采样。





动态采样提供11个设置级别。注意:9i中其默认值为1 到了10g默认值为2





2、动态采样如何工作?

有两种使用方式:

△ 设置OPTIMIZER_DYNAMIC_SAMPLING参数,可以再实例和会话级别设置动态采样。

△ 使用DYNAMIC_SAMPLING hint





来看一下不使用动态采样的日子怎么过的

create table t

as

select owner, object_type

from all_objects

/









select count(*) from t;





  COUNT(*)

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

      68076





code1: 禁用动态采样观察默认基数





set autotrace traceonly explain

SQL> select /*+ dynamic_sampling(t 0) */ * from t;





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 16010 |   437K|    55   (0)| 00:00:01 |

|   1 |  TABLE ACCESS FULL| T    | 16010 |   437K|    55   (0)| 00:00:01 |

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





--注意0级别即为禁用动态采样,环境默认是开启动态采样的





执行计划显示基数:16010远低于上面查询的68076,明显不靠谱。





code2: 更加接近显示的基数

select * from t;





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 77871 |  2129K|    56   (2)| 00:00:01 |

|   1 |  TABLE ACCESS FULL| T    | 77871 |  2129K|    56   (2)| 00:00:01 |

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





Note

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

- dynamic sampling used for this statement









code3: 被高估的基数

SQL> delete from t; 

68076 rows deleted. 





SQL> commit; 

Commit complete. 





SQL> set autotrace traceonly explain

SQL> select /*+ dynamic_sampling(t 0) */ * from t;





Execution Plan 

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 16010 |   437K|    55   (0)| 00:00:01 |

|   1 |  TABLE ACCESS FULL| T    | 16010 |   437K|    55   (0)| 00:00:01 |

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





SQL> select * from t;





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      |     1 |    28 |    55   (0)| 00:00:01 |

|   1 |  TABLE ACCESS FULL| T    |     1 |    28 |    5    (0)| 00:00:01 |

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





Note

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

- dynamic sampling used for this statement









3、动态采样何时帮助优化器验证其猜测?

我们知道当使用DBMS_STATS收集了表信息后,优化器会得到以下统计:

1)表,行数,平均行宽等;

2)单独列,高低值,唯一值数量,直方图(可能)等;

3)单独索引,聚集因素,叶子块数量,索引高度等。





但注意这里面缺少了某些关键统计信息,例如表中不同列数据之间的关联!

假设你你有一个全球人口普查表!

一个属性是:出生月份MONTH_BORN_IN,另一个属性是:所属星座ZODIAC_SIGN。收集信息后,你问优化器出生在11月份的人数?

假设12个月人数正常分布,那么优化器很快给出答案是全量数据的1/12!再问一个:星座是双鱼座的人数呢?答案也是1/12!

迄今为止优化器对答如流!!!nice work!

但是第3个问题来了:出生在11月份并且星座是双鱼座的人数是多少呢?

明眼人转下脑子就知道答案是0(双鱼座2月19日-3月20日)!但是我们看优化器的答案:1/12/12!!! 多么异想天开的答案,思维定式!这样就会诞生差的执行计划,

也正是在此时我们的动态采样开始干预:





code4: 创建模拟数据

SQL > create table t

  as select decode( mod(rownum,2), 0, 'N', 'Y' ) flag1,

               decode( mod(rownum,2), 0, 'Y', 'N' ) flag2, a.*

    from all_objects a

/

Table created.





SQL > create index t_idx on t(flag1,flag2);

Index created.





SQL > begin

         dbms_stats.gather_table_stats

         ( user, 'T',

         method_opt=>'for all indexed columns size 254' );

end;

/

PL/SQL procedure successfully completed.





SQL> select num_rows, num_rows/2, 

num_rows/2/2 from user_tables 

where table_name = 'T';





NUM_ROWS  NUM_ROWS/2  NUM_ROWS/2/2

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

   68076       34038         17019





code5:验证一下上面的说法:

SQL> set autotrace traceonly explain

SQL> select * from t where flag1='N';





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 33479 |  3432K|   292   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| T    | 33479 |  3432K|   292   (1)| 00:00:04 |

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





Predicate Information (identified by operation id):

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

   1 - filter("FLAG1"='N')





SQL> select * from t where flag2='N';





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 34597 |   3547K|   292   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| T    | 34597 |   3547K|   292   (1)| 00:00:04 |

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





Predicate Information (identified by operation id):

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





   1 - filter("FLAG2"='N')





--至此一切正常!so far, so good!





code5: here comes the problem   

SQL> select * from t where flag1 = 'N' and flag2 = 'N';





Execution Plan

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

Plan hash value: 1601196873





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

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

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

|   0 | SELECT STATEMENT  |      | 17014 |  1744K|   292   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| T    | 17014 |  1744K|   292   (1)| 00:00:04 |

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





Predicate Information (identified by operation id):

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





   1 - filter("FLAG1" = 'N' AND "FLAG2" = 'N')





--验证了我们前面说的优化器此时异想天开了





code7: 动态采样听令,开始介入

SQL> select /*+ dynamic_sampling(t 3) */ * from t where flag1 = 'N' and flag2 = 'N';





Execution Plan

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

Plan hash value: 470836197





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

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

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

|   0 | SELECT STATEMENT            |       |    6 |   630 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T     |    6 |   630 |     2   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | T_IDX |    6 |       |     1   (0)| 00:00:01 |

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





Predicate Information (identified by operation id):

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





   2 - access("FLAG1"='N' AND "FLAG2"='N')





code8: 我们打开SQL_TRACE会看到以下语句:

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"), NVL(SUM(C3),:"SYS_B_02")

FROM

  (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T") FULL("T")

   NO_PARALLEL_INDEX("T") */ :"SYS_B_03" AS C1, CASE WHEN "T"."FLAG1"=

   :"SYS_B_04" AND "T"."FLAG2"=:"SYS_B_05" THEN :"SYS_B_06" ELSE :"SYS_B_07"

   END AS C2, CASE WHEN "T"."FLAG2"=:"SYS_B_08" AND "T"."FLAG1"=:"SYS_B_09"

   THEN :"SYS_B_10" ELSE :"SYS_B_11" END AS C3 FROM "T" SAMPLE BLOCK

   (:"SYS_B_12" , :"SYS_B_13") SEED (:"SYS_B_14") "T") SAMPLESUB   

   

可以看出来优化器在验证其猜想。。。   

   

   

4、动态采样级别:

现在列出11个级别,详细请参考:http://docs.oracle.com/cd/B19306_01/server.102/b14211/stats.htm#i43032

1)Level 0: Do not use dynamic sampling. 

0级:不使用动态采样。





2)Level 1: Sample all tables that have not been analyzed if the following criteria are met: (1) there is at least 1 unanalyzed table in the query; (2) this unanalyzed table is joined to another table or appears in a subquery or non-mergeable view; (3) this unanalyzed table has no indexes; (4) this unanalyzed table has more blocks than the number of blocks that would be used for dynamic sampling of this table. The number of blocks sampled is the default number of dynamic sampling blocks (32).

1级:满足以下条件则采样所有没被分析的表:

(1)查询中至少有一个未分析表;

(2)这个未分析表被关联另外一个表或者出现在子查询或非merge视图中;

(3)这个未分析表有索引;

(4)这个未分析表有多余动态采样默认的数据块数(默认是32块)。





3)Level 2: Apply dynamic sampling to all unanalyzed tables. The number of blocks sampled is two times the default number of dynamic sampling blocks.

2级:对所有未分析表进行动态采样。采样数据块数量是默认数量的2倍。





4)Level 3: Apply dynamic sampling to all tables that meet Level 2 criteria, plus all tables for which standard selectivity estimation used a guess for some predicate that is a potential dynamic sampling predicate. The number of blocks sampled is the default number of dynamic sampling blocks. For unanalyzed tables, the number of blocks sampled is two times the default number of dynamic sampling blocks.

3级:在2级基础上加上那些使用了猜想选择消除表,采样数据块数量等于默认数量。对于未分析表,采样数量2倍于默认数量。









5)Level 4: Apply dynamic sampling to all tables that meet Level 3 criteria, plus all tables that have single-table predicates that reference 2 or more columns. The number of blocks sampled is the default number of dynamic sampling blocks. For unanalyzed tables, the number of blocks sampled is two times the default number of dynamic sampling blocks.

4级:在3级基础上加上那些有单表谓词关联2个或多个列,采样数据块数量等于默认数量。对于未分析表,采样数量2倍于默认数量。









6)Levels 5, 6, 7, 8, and 9: Apply dynamic sampling to all tables that meet the previous level criteria using 2, 4, 8, 32, or 128 times the default number of dynamic sampling blocks respectively.

5,6,7,8,9级在4级基础上分别使用2,4,8,32,128倍于默认动态采样数据块数量。





7)Level 10: Apply dynamic sampling to all tables that meet the Level 9 criteria using all blocks in the table.

10级:在9级基础上对表中所有数据块进行采样。





5、什么时候适合采用动态采样?





这是一个狡猾的问题,没有一定使用经验,还真不好意思说。

通常:

1)我们使用3和4级进行动态采样。

2)如果我们SQL的解析时间很快但是执行时间巨慢,可以考虑使用动态采样。典型的就是数据仓库系统。

3)OLTP系统中都是一个SQL重复执行,解析和执行都在瞬息之间,所以不建议使用高级别的动态采样。这会给SQL带来硬解析消耗。

这个时候可以考虑SQL Profile,你可以理解为“静态采样”。

关于SQL Profiles参考:http://docs.oracle.com/cd/B28359_01/server.111/b28274/sql_tune.htm#PFGRF02605

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

Dylan    Presents.

关于动态抽样(Dynamic Sampling)的更多相关文章

  1. 使用动态类型dynamic让你的省了很多临时类

    客户端与服务端的数据交互使用的数据格式是json格式,为了使客户端与服务端有类对应关系,进行序列化,所以总要定义一些类,使用动态类型dynamic可以不必要定义那么多类. 测试代码: using Sy ...

  2. Java的动态代理(dynamic proxy)

    什么是动态代理(dynamic proxy) 动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对 ...

  3. [大牛翻译系列]Hadoop(7)MapReduce:抽样(Sampling)

    4.3 抽样(Sampling) 用基于MapReduce的程序来处理TB级的数据集,要花费的时间可能是数以小时计.仅仅是优化代码是很难达到良好的效果. 在开发和调试代码的时候,没有必要处理整个数据集 ...

  4. 动态类(Dynamic)应用

    动态类(Dynamic)应用 背景: 在Coding中有时候会遇到一些需要解析的数据,可是数据的字段数量和名称未统一,我们没法定义实体类来对应.那么我们就会想到通过C#的dynamic动态类来实现,如 ...

  5. C# 匿名对象(匿名类型)、var、动态类型 dynamic

    本文是要写的下篇<C#反射及优化用法>的前奏,不能算是下一篇文章的基础的基础吧,有兴趣的朋友可以关注一下. 随着C#的发展,该语音内容不断丰富,开发变得更加方便快捷,C# 的锋利尽显无疑. ...

  6. ES 12 - 配置使用Elasticsearch的动态映射 (dynamic mapping)

    目录 1 动态映射(dynamic mapping) 1.1 什么是动态映射 1.2 体验动态映射 1.3 搜索结果不一致的原因分析 2 开启dynamic mapping策略 2.1 约束策略 2. ...

  7. C# 匿名对象(匿名类型)、var、动态类型 dynamic——实用之:过滤类属性、字段实用dynamic

    例子 返回一个LIst<oject>类型 而oject含有 30个字段 而我只需要两个字段.这里实用dynamic 和 linq. 上代码: 注意select new {} 为匿名类型,这 ...

  8. 水塘抽样(Reservoir Sampling)问题

    水塘抽样是一系列的随机算法,其目的在于从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数量,尤其适用于不能把所有n个项目都存放到主内存的情况. 在高德纳的计算机程序设计艺术中,有如下问题: ...

  9. c# 把一个匿名对象赋值给一个Object类型的变量后,怎么取这个变量? c# dynamic动态类型和匿名类 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic 深入浅析C#中的var和dynamic

    比如有一个匿名对象,var  result =......Select( a=>new {  id=a.id, name=a.name});然后Object  obj =  result ;我怎 ...

  10. Asp.Net SignalR 使用记录 技术回炉重造-总纲 动态类型dynamic转换为特定类型T的方案 通过对象方法获取委托_C#反射获取委托_ .net core入门-跨域访问配置

    Asp.Net SignalR 使用记录   工作上遇到一个推送消息的功能的实现.本着面向百度编程的思想.网上百度了一大堆.主要的实现方式是原生的WebSocket,和SignalR,再次写一个关于A ...

随机推荐

  1. 从零开始配置 vim(5)——本地设置与全局设置

    在前面的一系列文章中,我们介绍了使用 :noremap 进行键盘映射,使用 set 来设置选项和 vim 的变量.并且已经在配置文件中对他们进行了相关配置. 在介绍设置那一篇文章中我们提到了,lua ...

  2. 设计模式学习-使用go实现责任链模式

    责任链模式 定义 优点 缺点 适用范围 代码实现 责任链模式对比装饰模式 参考 责任链模式 定义 责任链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免请求 ...

  3. 【主流技术】聊一聊对 Mybatis Plus 的理解与应用

    前言 mybatis plus是一个mybatis的增强工具,在其基础上只做增强不做改变.作为开发中常见的第三方组件,学习并应用在项目中可以节省开发时间,提高开发效率. 官方文档地址:MyBatis- ...

  4. 基于无监督训练SimCSE+In-batch Negatives策略有监督训练的语义索引召回

    基于无监督训练SimCSE+In-batch Negatives策略有监督训练的语义索引召回 语义索引(可通俗理解为向量索引)技术是搜索引擎.推荐系统.广告系统在召回阶段的核心技术之一.语义索引模型的 ...

  5. Python 实现Ping命令状态检测

    ping 是一种因特网包探索器,用于测试网络连接量的程序,Ping是工作在TCP/IP网络体系结构中应用层的一个服务命令,主要是向特定的目的主机发送 ICMP 请求报文,测试目的站是否可达及了解其有关 ...

  6. Python 检测PE所启用保护方式

    Python 通过pywin32模块调用WindowsAPI接口,实现对特定进程加载模块的枚举输出并检测该PE程序模块所启用的保护方式,此处枚举输出的是当前正在运行进程所加载模块的DLL模块信息,需要 ...

  7. 打造个性化日历:Python编程实现,选择适合你的方式!

    在本文中,我们将使用Python编写一个简单的日历程序.虽然市面上已经存在现成的日历功能,并且有第三方库可以直接调用实现,但我们仍然希望通过自己编写日历程序来引出我认为好用的日历实现.希望这篇文章能够 ...

  8. 使用 WPF + Chrome 内核实现高稳定性的在线客服系统复合应用程序

    对于在线客服与营销系统,客服端指的是后台提供服务的客服或营销人员,他们使用客服程序在后台观察网站的被访情况,开展营销活动或提供客户服务.在本篇文章中,我将详细介绍如何通过 WPF + Chrome 内 ...

  9. 数学问题,2的n次方 - 1 是怎么来的? 通常用作计算数值

  10. Linux-数据集 TPC-H、TPC-DS的导入和使用(MySQL)

    一. TPC-H 数据集 1.数据集下载 TPC-H数据集: https://github.com/gregrahn/tpch-kit 可采用gcc下载或者直接下载zip包,然后解压即可. 具体使用方 ...