程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> oracle直方圖

oracle直方圖

編輯:Oracle教程

oracle直方圖


直方圖 
當某列數據分布不均衡,為了讓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%准確。
  
相關的@腳本在文章的最後面提供。


SQL> drop table a;

表已刪除。

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

表已創建。

SQL> @anatab                        --常規的表分析
輸入 ownname 的值:  ggs
輸入 tabname 的值:  a
輸入 estimate_percent 的值:  100
輸入 skewonly_repeat_auto 的值:  auto
輸入 degree 的值:  4

PL/SQL 過程已成功完成。

已用時間:  00: 00: 00.26
SQL> @getcolstat                    --字段的直方圖
輸入 owner 的值:  ggs
輸入 table_name 的值:  a

COLUMN_NAME        NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM NUM_BUCKETS LAST_ANALYZED   
---------------- ---------- ----------- ----------- --------------------- --------------  
SECONDARY             10000           1         .01 NONE                1 28-7月 -14      
GENERATED             10000           2         .02 NONE                1 28-7月 -14      
TEMPORARY             10000           2         .02 NONE                1 28-7月 -14      
STATUS                10000           1         .01 NONE                1 28-7月 -14      
TIMESTAMP             10000         350         3.5 NONE                1 28-7月 -14      
LAST_DDL_TIME         10000         385        3.85 NONE                1 28-7月 -14      
CREATED               10000         303        3.03 NONE                1 28-7月 -14      
OBJECT_TYPE           10000          34         .34 NONE                1 28-7月 -14      
DATA_OBJECT_ID        10000        1836       18.36 NONE                1 28-7月 -14      
OBJECT_ID             10000       10000         100 NONE                1 28-7月 -14      
SUBOBJECT_NAME        10000          27         .27 NONE                1 28-7月 -14      
OBJECT_NAME           10000        7725       77.25 NONE                1 28-7月 -14      
OWNER                 10000           9         .09 NONE                1 28-7月 -14      

已選擇13行。

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

OBJECT_TYPE           COUNT(*)
------------------- ----------
INDEX                      946
JOB CLASS                    2
CONTEXT                      2
TYPE BODY                   82
PROCEDURE                   50
RESOURCE PLAN                3
RULE                         1
SCHEDULE                     1
TABLE PARTITION             52
WINDOW                       2
WINDOW GROUP                 1
TABLE                      841
TYPE                      1088
VIEW                      2953
LIBRARY                    113
FUNCTION                    68
TRIGGER                      5
PROGRAM                      3
CLUSTER                     10
SYNONYM                   2458
PACKAGE BODY               470
QUEUE                       21
CONSUMER GROUP               5
EVALUATION CONTEXT           8
RULE SET                    11
DIRECTORY                    2
UNDEFINED                    6
OPERATOR                    15
SEQUENCE                   102
LOB                        128
PACKAGE                    485
JOB                          6
INDEX PARTITION             59
LOB PARTITION                1

已選擇34行。

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

已解釋。

SQL> @getplan
'general,outline,starts'

Enter value for plan type:general

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------

Plan hash value: 2223038180

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |     7 |    25   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS FULL| A    |   294 |  2058 |    25   (0)| 00:00:01 | --跟實際不一致,上面查出來的是946
---------------------------------------------------------------------------

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

   2 - filter("OBJECT_TYPE"='INDEX')
SQL> select 10000/34 from dual;    --說明rows中的294是 估算值=總行數/字段distinct值的個數

  10000/34
----------
294.117647

已選擇 1 行。

SQL>
SQL> @anatab_col
輸入 owner 的值:  ggs
輸入 table_name 的值:  a
輸入 columns 的值:  object_type     --做object_type字段的直方圖

PL/SQL 過程已成功完成。

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

已解釋。

SQL> @getplan
'general,outline,starts'

Enter value for plan type:general

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------

Plan hash value: 2223038180

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |     7 |    25   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |     7 |            |          |
|*  2 |   TABLE ACCESS FULL| A    |   946 |  6622 |    25   (0)| 00:00:01 |   --這裡返回的是真實的行數,做object_type字段的直方圖後,執行計劃非常准。
---------------------------------------------------------------------------

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

   2 - filter("OBJECT_TYPE"='INDEX')
SQL>
SQL>
SQL>
SQL>
SQL> @getcolstat
輸入 owner 的值:  ggs
輸入 table_name 的值:  a


COLUMN_NAME         NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM       NUM_BUCKETS LAST_ANALYZED
---------------- ---------- ----------- ----------- --------- ----------- --------------      
SECONDARY             10000           1         .01 NONE                1 28-7月 -14          
GENERATED             10000           2         .02 NONE                1 28-7月 -14          
TEMPORARY             10000           2         .02 NONE                1 28-7月 -14          
STATUS                10000           1         .01 NONE                1 28-7月 -14          
TIMESTAMP             10000         350         3.5 NONE                1 28-7月 -14          
LAST_DDL_TIME         10000         385        3.85 NONE                1 28-7月 -14          
CREATED               10000         303        3.03 NONE                1 28-7月 -14          
OBJECT_TYPE           10000          34         .34 FREQUENCY          34 28-7月 -14   --剛好等於distinct值
DATA_OBJECT_ID        10000        1836       18.36 NONE                1 28-7月 -14          
OBJECT_ID             10000       10000         100 NONE                1 28-7月 -14          
SUBOBJECT_NAME        10000          27         .27 NONE                1 28-7月 -14          
OBJECT_NAME           10000        7725       77.25 NONE                1 28-7月 -14          
OWNER                 10000           9         .09 NONE                1 28-7月 -14      
    
已選擇13行。


SQL> select count(distinct object_name) from a;    --總共才10000行,可以看出object_name的選擇性是比較高的

COUNT(DISTINCTOBJECT_NAME)
--------------------------
                      7725

已選擇 1 行。

SQL> @anatab_col
輸入 owner 的值:  ggs
輸入 table_name 的值:  a
輸入 columns 的值:   object_name

PL/SQL 過程已成功完成。

SQL> @getcolstat
輸入 owner 的值:  ggs
輸入 table_name 的值:  a

COLUMN_NAME         NUM_ROWS CARDINALITY SELECTIVITY HISTOGRAM       NUM_BUCKETS LAST_ANALYZED  
---------------- ---------- ----------- ----------- --------------- ----------- --------------  
SECONDARY             10000           1         .01 NONE                      1 28-7月 -14      
GENERATED             10000           2         .02 NONE                      1 28-7月 -14      
TEMPORARY             10000           2         .02 NONE                      1 28-7月 -14      
STATUS                10000           1         .01 NONE                      1 28-7月 -14      
TIMESTAMP             10000         350         3.5 NONE                      1 28-7月 -14      
LAST_DDL_TIME         10000         385        3.85 NONE                      1 28-7月 -14      
CREATED               10000         303        3.03 NONE                      1 28-7月 -14      
OBJECT_TYPE           10000          34         .34 FREQUENCY                34 28-7月 -14      
DATA_OBJECT_ID        10000        1836       18.36 NONE                      1 28-7月 -14      
OBJECT_ID             10000       10000         100 NONE                      1 28-7月 -14      
SUBOBJECT_NAME        10000          27         .27 NONE                      1 28-7月 -14      
OBJECT_NAME           10000        7725       77.25 HEIGHT BALANCED          75 28-7月 -14      
OWNER                 10000           9         .09 NONE                      1 28-7月 -14      

已選擇13行。


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

  COUNT(*)
----------
      6404

已選擇 1 行。

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

已解釋。

SQL> @getplan
'general,outline,starts'

Enter value for plan type:general

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------

Plan hash value: 2223038180

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

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

   2 - filter("OBJECT_NAME" LIKE '%A%')     --LIKE '%A%'對於cbo而言太復雜了,沒有真正跑的話,cbo根本不知道真正返回多少行。
SQL> 


已選擇13行。


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

OBJECT_NAME                      COUNT(*)
------------------------------ ----------
DBMS_REPCAT_AUTH                        5

已選擇 1 行。


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

已解釋。

SQL> @getplan
'general,outline,starts'

Enter value for plan type:general

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------

Plan hash value: 2223038180

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    19 |    25   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |    19 |            |          |
|*  2 |   TABLE ACCESS FULL| A    |     1 |    19 |    25   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   2 - filter("OBJECT_NAME"='DBMS_REPCAT_AUTH')   --這個不復雜了吧,rows=1,一樣不准,直方圖也不可能保證100%准確的

所以說,並不是所有字段都適合做直方圖。distinct值非常多的,根本不適合做直方圖,默認的桶數也裝不下。
只有字段值傾斜非常嚴重,distinct值少,而且用到的sql中where條件包含了這個字段。如果sql中都沒有用到這個字段,那也沒必要做直方圖,
因為做直方圖是非常cpu性能的。

@腳本
--anatab.sql
set timing on
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(ownname          => '&ownname',
                                tabname          => '&tabname' ,
                                estimate_percent => &estimate_percent,
                                method_opt       => 'for all columns size &skewonly_repeat_auto',
                                no_invalidate    => FALSE,
                                degree           => °ree,
                                cascade          => TRUE);
END;
/
set timing off


--anatab_col.sql
BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(ownname          => '&owner',
                                tabname          => '&table_name',
                                estimate_percent => 100,
                                method_opt       => 'for columns &columns ',  --such as:col1,col2,col3...
                                no_invalidate    => FALSE,
                                degree           => 4,
                                granularity      => 'ALL',
                                cascade          => TRUE);
END;
/

--getcolstat.sql
col COLUMN_NAME for a30
select a.column_name,
       b.num_rows,
       a.num_distinct Cardinality,
       round(a.num_distinct / b.num_rows * 100, 2) selectivity,
       a.histogram,
       a.num_buckets,
       a.last_analyzed
  from dba_tab_col_statistics a, dba_tables b
 where a.owner = b.owner
   and a.table_name = b.table_name
   and a.owner = upper('&owner')
   and a.table_name = upper('&table_name');  



--getplan.sql
set feedback off
pro 'general,outline,starts'
pro
acc type prompt 'Enter value for plan type:' default 'general'
select * from table(dbms_xplan.display) where '&&type'='general';
select * from table(dbms_xplan.display(null, null,'advanced -projection')) where '&&type'='outline';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS LAST')) where '&&type'='starts';
set feedback on
undef type











  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved