搜索
查看: 1341|: 0

【Oracle】oracle直方图

[复制链接]

183

主题

8

回帖

820

积分

高级会员

积分
820
发表于 2014-10-28 11:18:52 | 显示全部楼层 |阅读模式

直方图
当某列数据分布不均衡,为了让CBO能生成最佳的执行计划,我们可能需要对表收集直方图,直方图最大的桶数(Bucket)是254。收集直方图是一个很耗时的过程,如无必要,千万别去收集直方图。Oracle的直方图有两种:一种是频率直方图(FREQUENCY HISTOGRAM),当列中Distinct_keys 较少(小于254),如果不手工指定直方图桶数(BUCKET),Oracle就会自动的创建频率直方图,并且桶数(BUCKET)等于Distinct_Keys。一种是高度平衡直方图(HEIGHT BALANCED),当列中Distinct_keys大于254,如果不手工指定直方图桶数(BUCKET),Oracle就会自动的创建高度平衡直方图。直方图用在什么情况下?  列的值分布非常不均衡的时候,并且where条件中经常用到这个列。直方图都准吗?  不一定。如果一个字段distinct值的个数非常多,基本接近主键的distinct值的个数,就没必要做直方图,直方图也不一定100%准确。

  1. SQL> drop table a;

  2. 表已删除。

  3. SQL> create table a as select * from dba_objects where rownum<=10000;

  4. 表已创建。

  5. SQL> @anatab                        --常规的表分析
  6. 输入 ownname 的值:  ggs
  7. 输入 tabname 的值:  a
  8. 输入 estimate_percent 的值:  100
  9. 输入 skewonly_repeat_auto 的值:  auto
  10. 输入 degree 的值:  4

  11. PL/SQL 过程已成功完成。

  12. 已用时间:  00: 00: 00.26
  13. SQL> @getcolstat                    --字段的直方图
  14. 输入 owner 的值:  ggs
  15. 输入 table_name 的值:  a

  16. COLUMN_NAME        NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM NUM_BUCKETS LAST_ANALYZED   
  17. ---------------- ---------- ----------- ----------- --------------------- --------------  
  18. SECONDARY             10000           1         .01 NONE                1 28-7月 -14      
  19. GENERATED             10000           2         .02 NONE                1 28-7月 -14      
  20. TEMPORARY             10000           2         .02 NONE                1 28-7月 -14      
  21. STATUS                10000           1         .01 NONE                1 28-7月 -14      
  22. TIMESTAMP             10000         350         3.5 NONE                1 28-7月 -14      
  23. LAST_DDL_TIME         10000         385        3.85 NONE                1 28-7月 -14      
  24. CREATED               10000         303        3.03 NONE                1 28-7月 -14      
  25. OBJECT_TYPE           10000          34         .34 NONE                1 28-7月 -14      
  26. DATA_OBJECT_ID        10000        1836       18.36 NONE                1 28-7月 -14      
  27. OBJECT_ID             10000       10000         100 NONE                1 28-7月 -14      
  28. SUBOBJECT_NAME        10000          27         .27 NONE                1 28-7月 -14      
  29. OBJECT_NAME           10000        7725       77.25 NONE                1 28-7月 -14      
  30. OWNER                 10000           9         .09 NONE                1 28-7月 -14      

  31. 已选择13行。

  32. SQL>
  33. SQL> select object_type,count(*) from a group by object_type;

  34. OBJECT_TYPE           COUNT(*)
  35. ------------------- ----------
  36. INDEX                      946
  37. JOB CLASS                    2
  38. CONTEXT                      2
  39. TYPE BODY                   82
  40. PROCEDURE                   50
  41. RESOURCE PLAN                3
  42. RULE                         1
  43. SCHEDULE                     1
  44. TABLE PARTITION             52
  45. WINDOW                       2
  46. WINDOW GROUP                 1
  47. TABLE                      841
  48. TYPE                      1088
  49. VIEW                      2953
  50. LIBRARY                    113
  51. FUNCTION                    68
  52. TRIGGER                      5
  53. PROGRAM                      3
  54. CLUSTER                     10
  55. SYNONYM                   2458
  56. PACKAGE BODY               470
  57. QUEUE                       21
  58. CONSUMER GROUP               5
  59. EVALUATION CONTEXT           8
  60. RULE SET                    11
  61. DIRECTORY                    2
  62. UNDEFINED                    6
  63. OPERATOR                    15
  64. SEQUENCE                   102
  65. LOB                        128
  66. PACKAGE                    485
  67. JOB                          6
  68. INDEX PARTITION             59
  69. LOB PARTITION                1

  70. 已选择34行。

  71. SQL> explain plan for select count(*) from a where object_type='INDEX';

  72. 已解释。

  73. SQL> @getplan
  74. 'general,outline,starts'

  75. Enter value for plan type:general

  76. PLAN_TABLE_OUTPUT
  77. ---------------------------------------------------------------------------------------------------------------------------------------

  78. Plan hash value: 2223038180

  79. ---------------------------------------------------------------------------
  80. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  81. ---------------------------------------------------------------------------
  82. |   0 | SELECT STATEMENT   |      |     1 |     7 |    25   (0)| 00:00:01 |
  83. |   1 |  SORT AGGREGATE    |      |     1 |     7 |            |          |
  84. |*  2 |   TABLE ACCESS FULL| A    |   294 |  2058 |    25   (0)| 00:00:01 | --跟实际不一致,上面查出来的是946
  85. ---------------------------------------------------------------------------

  86. Predicate Information (identified by operation id):
  87. ---------------------------------------------------

  88.    2 - filter("OBJECT_TYPE"='INDEX')
  89. SQL> select 10000/34 from dual;    --说明rows中的294是 估算值=总行数/字段distinct值的个数

  90.   10000/34
  91. ----------
  92. 294.117647

  93. 已选择 1 行。

  94. SQL>
  95. SQL> @anatab_col
  96. 输入 owner 的值:  ggs
  97. 输入 table_name 的值:  a
  98. 输入 columns 的值:  object_type     --做object_type字段的直方图

  99. PL/SQL 过程已成功完成。

  100. SQL> explain plan for select count(*) from a where object_type='INDEX';

  101. 已解释。

  102. SQL> @getplan
  103. 'general,outline,starts'

  104. Enter value for plan type:general

  105. PLAN_TABLE_OUTPUT
  106. ---------------------------------------------------------------------------------------------------------------------------------------

  107. Plan hash value: 2223038180

  108. ---------------------------------------------------------------------------
  109. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  110. ---------------------------------------------------------------------------
  111. |   0 | SELECT STATEMENT   |      |     1 |     7 |    25   (0)| 00:00:01 |
  112. |   1 |  SORT AGGREGATE    |      |     1 |     7 |            |          |
  113. |*  2 |   TABLE ACCESS FULL| A    |   946 |  6622 |    25   (0)| 00:00:01 |   --这里返回的是真实的行数,做object_type字段的直方图后,执行计划非常准。
  114. ---------------------------------------------------------------------------

  115. Predicate Information (identified by operation id):
  116. ---------------------------------------------------

  117.    2 - filter("OBJECT_TYPE"='INDEX')
  118. SQL>
  119. SQL>
  120. SQL>
  121. SQL>
  122. SQL> @getcolstat
  123. 输入 owner 的值:  ggs
  124. 输入 table_name 的值:  a


  125. COLUMN_NAME         NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM       NUM_BUCKETS LAST_ANALYZED
  126. ---------------- ---------- ----------- ----------- --------- ----------- --------------      
  127. SECONDARY             10000           1         .01 NONE                1 28-7月 -14         
  128. GENERATED             10000           2         .02 NONE                1 28-7月 -14         
  129. TEMPORARY             10000           2         .02 NONE                1 28-7月 -14         
  130. STATUS                10000           1         .01 NONE                1 28-7月 -14         
  131. TIMESTAMP             10000         350         3.5 NONE                1 28-7月 -14         
  132. LAST_DDL_TIME         10000         385        3.85 NONE                1 28-7月 -14         
  133. CREATED               10000         303        3.03 NONE                1 28-7月 -14         
  134. OBJECT_TYPE           10000          34         .34 FREQUENCY          34 28-7月 -14   --刚好等于distinct值
  135. DATA_OBJECT_ID        10000        1836       18.36 NONE                1 28-7月 -14         
  136. OBJECT_ID             10000       10000         100 NONE                1 28-7月 -14         
  137. SUBOBJECT_NAME        10000          27         .27 NONE                1 28-7月 -14         
  138. OBJECT_NAME           10000        7725       77.25 NONE                1 28-7月 -14         
  139. OWNER                 10000           9         .09 NONE                1 28-7月 -14      
  140.    
  141. 已选择13行。


  142. SQL> select count(distinct object_name) from a;    --总共才10000行,可以看出object_name的选择性是比较高的

  143. COUNT(DISTINCTOBJECT_NAME)
  144. --------------------------
  145.                       7725

  146. 已选择 1 行。

  147. SQL> @anatab_col
  148. 输入 owner 的值:  ggs
  149. 输入 table_name 的值:  a
  150. 输入 columns 的值:   object_name

  151. PL/SQL 过程已成功完成。

  152. SQL> @getcolstat
  153. 输入 owner 的值:  ggs
  154. 输入 table_name 的值:  a

  155. COLUMN_NAME         NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM       NUM_BUCKETS LAST_ANALYZED  
  156. ---------------- ---------- ----------- ----------- --------------- ----------- --------------  
  157. SECONDARY             10000           1         .01 NONE                      1 28-7月 -14      
  158. GENERATED             10000           2         .02 NONE                      1 28-7月 -14      
  159. TEMPORARY             10000           2         .02 NONE                      1 28-7月 -14      
  160. STATUS                10000           1         .01 NONE                      1 28-7月 -14      
  161. TIMESTAMP             10000         350         3.5 NONE                      1 28-7月 -14      
  162. LAST_DDL_TIME         10000         385        3.85 NONE                      1 28-7月 -14      
  163. CREATED               10000         303        3.03 NONE                      1 28-7月 -14      
  164. OBJECT_TYPE           10000          34         .34 FREQUENCY                34 28-7月 -14      
  165. DATA_OBJECT_ID        10000        1836       18.36 NONE                      1 28-7月 -14      
  166. OBJECT_ID             10000       10000         100 NONE                      1 28-7月 -14      
  167. SUBOBJECT_NAME        10000          27         .27 NONE                      1 28-7月 -14      
  168. OBJECT_NAME           10000        7725       77.25 HEIGHT BALANCED          75 28-7月 -14      
  169. OWNER                 10000           9         .09 NONE                      1 28-7月 -14      

  170. 已选择13行。


  171. SQL> select count(*) from a where object_name like '%A%';

  172.   COUNT(*)
  173. ----------
  174.       6404

  175. 已选择 1 行。

  176. SQL> explain plan for select count(*) from a where object_name like '%A%';

  177. 已解释。

  178. SQL> @getplan
  179. 'general,outline,starts'

  180. Enter value for plan type:general

  181. PLAN_TABLE_OUTPUT
  182. --------------------------------------------------------------------------------------------------------------

  183. Plan hash value: 2223038180

  184. ---------------------------------------------------------------------------
  185. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  186. ---------------------------------------------------------------------------
  187. |   0 | SELECT STATEMENT   |      |     1 |    19 |    25   (0)| 00:00:01 |
  188. |   1 |  SORT AGGREGATE    |      |     1 |    19 |            |          |
  189. |*  2 |   TABLE ACCESS FULL| A    |   500 |  9500 |    25   (0)| 00:00:01 |
  190. ---------------------------------------------------------------------------

  191. Predicate Information (identified by operation id):
  192. ---------------------------------------------------

  193.    2 - filter("OBJECT_NAME" LIKE '%A%')     --LIKE '%A%'对于cbo而言太复杂了,没有真正跑的话,cbo根本不知道真正返回多少行。
  194. SQL>


  195. 已选择13行。


  196. SQL> col OBJECT_NAME for a30
  197. SQL> select OBJECT_NAME,count(*) from a group by OBJECT_NAME having count(*)>3 order by count(*) desc;

  198. OBJECT_NAME                      COUNT(*)
  199. ------------------------------ ----------
  200. DBMS_REPCAT_AUTH                        5

  201. 已选择 1 行。


  202. SQL> explain plan for select count(*) from a where OBJECT_NAME='DBMS_REPCAT_AUTH';

  203. 已解释。

  204. SQL> @getplan
  205. 'general,outline,starts'

  206. Enter value for plan type:general

  207. PLAN_TABLE_OUTPUT
  208. ---------------------------------------------------------------------------------------------------------

  209. Plan hash value: 2223038180

  210. ---------------------------------------------------------------------------
  211. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  212. ---------------------------------------------------------------------------
  213. |   0 | SELECT STATEMENT   |      |     1 |    19 |    25   (0)| 00:00:01 |
  214. |   1 |  SORT AGGREGATE    |      |     1 |    19 |            |          |
  215. |*  2 |   TABLE ACCESS FULL| A    |     1 |    19 |    25   (0)| 00:00:01 |
  216. ---------------------------------------------------------------------------

  217. Predicate Information (identified by operation id):
  218. ---------------------------------------------------

  219.    2 - filter("OBJECT_NAME"='DBMS_REPCAT_AUTH')   --这个不复杂了吧,rows=1,一样不准,直方图也不可能保证100%准确的

  220. 所以说,并不是所有字段都适合做直方图。distinct值非常多的,根本不适合做直方图,默认的桶数也装不下。
  221. 只有字段值倾斜非常严重,distinct值少,而且用到的sql中where条件包含了这个字段。如果sql中都没有用到这个字段,那也没必要做直方图,
  222. 因为做直方图是非常cpu性能的。

  223. @脚本
  224. --anatab.sql
  225. set timing on
  226. BEGIN
  227.   DBMS_STATS.GATHER_TABLE_STATS(ownname          => '&ownname',
  228.                                 tabname          => '&tabname' ,
  229.                                 estimate_percent => &estimate_percent,
  230.                                 method_opt       => 'for all columns size &skewonly_repeat_auto',
  231.                                 no_invalidate    => FALSE,
  232.                                 degree           => °ree,
  233.                                 cascade          => TRUE);
  234. END;
  235. /
  236. set timing off


  237. --anatab_col.sql
  238. BEGIN
  239.   DBMS_STATS.GATHER_TABLE_STATS(ownname          => '&owner',
  240.                                 tabname          => '&table_name',
  241.                                 estimate_percent => 100,
  242.                                 method_opt       => 'for columns &columns ',  --such as:col1,col2,col3...
  243.                                 no_invalidate    => FALSE,
  244.                                 degree           => 4,
  245.                                 granularity      => 'ALL',
  246.                                 cascade          => TRUE);
  247. END;
  248. /

  249. --getcolstat.sql
  250. col COLUMN_NAME for a30
  251. select a.column_name,
  252.        b.num_rows,
  253.        a.num_distinct Cardinality,
  254.        round(a.num_distinct / b.num_rows * 100, 2) selectivity,
  255.        a.histogram,
  256.        a.num_buckets,
  257.        a.last_analyzed
  258.   from dba_tab_col_statistics a, dba_tables b
  259. where a.owner = b.owner
  260.    and a.table_name = b.table_name
  261.    and a.owner = upper('&owner')
  262.    and a.table_name = upper('&table_name');  



  263. --getplan.sql
  264. set feedback off
  265. pro 'general,outline,starts'
  266. pro
  267. acc type prompt 'Enter value for plan type:' default 'general'
  268. select * from table(dbms_xplan.display) where '&&type'='general';
  269. select * from table(dbms_xplan.display(null, null,'advanced -projection')) where '&&type'='outline';
  270. SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS LAST')) where '&&type'='starts';
  271. set feedback on
  272. undef type
复制代码



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

大数据中国微信

QQ   

版权所有: Discuz! © 2001-2013 大数据.

GMT+8, 2024-11-15 20:50 , Processed in 0.053763 second(s), 24 queries .

快速回复 返回顶部 返回列表