版權聲明:本文發佈於http://www.cnblogs.com/yumiko/,版權由Yumiko_sunny所有,歡迎轉載。轉載時,請在文章明顯位置註明原文鏈接。若在未經作者同意的情況下,將本文內容用於商業用途,將保留追究其法律責任的權利。如果有問題,請以郵箱方式聯繫作者(793113046@q ...
版權聲明:本文發佈於http://www.cnblogs.com/yumiko/,版權由Yumiko_sunny所有,歡迎轉載。轉載時,請在文章明顯位置註明原文鏈接。若在未經作者同意的情況下,將本文內容用於商業用途,將保留追究其法律責任的權利。如果有問題,請以郵箱方式聯繫作者([email protected])。
前言
- 針對索引列,尤其是存在嚴重數據傾斜的索引列,直方圖的統計信息,對於CBO優化器更準確地選擇執行計劃至關重要。
- 對於初心者,可以從這篇文章中,瞭解到直方圖對於索引列的價值、作用,以及使用技巧。
- 對於經驗者,同樣可以從文章中,瞭解到不同的analyze table操作,對於直方圖信息統計的影響。該部分也可以直接查閱本篇文章最後的總結篇。
- 先強調一句:analyze table table_name compute statistics這個操作要謹慎!
1、直方圖概述
- 直方圖作為一種計量數據分佈的統計工具,並非ORACLE專有。
- 對於ORACLE而言,直方圖主要用於在分析表以及索引時,統計相關列上的數據,記錄該列整體的數據分佈情況。
2、直方圖的分類
- ORACLE的直方圖主要有兩種,等頻直方圖以及等高直方圖
- 預設情況下,當列上的唯一值數量低於254個,ORACLE會建立等頻直方圖。
- 預設情況下,當列上的唯一值數量高於254個,ORACLE會建立等高直方圖。
- 可以在執行dbms_stats.gather_table_stats收集統計信息時,通過method_opt參數,設置SIZE低於目標列的唯一值數量,從而使用等高直方圖。
3、直方圖的優勢
對於ORACLE而言,CBO優化器可以根據直方圖收集的列值分佈信息,讓選擇性高(返回數據行比例少)的列值使用索引,而選擇性低(返回數據行比例多)的列值不使用索引。尤其對於存在數據傾斜嚴重的列而言,直方圖很重要。
註:數據傾斜,主要指某列上的一個數值,相較於該列其他數值,出現比例高,如:“性別”列,“男性”占到該列整體數值(男性、女性)的80%,存在明顯的數據傾斜現象。
4、直方圖適用範圍
一般而言,直方圖不受是否使用索引的限制,即可以用來統計索引列,也可以統計非索引列。但對於非索引列的統計,意義不大。
5、直方圖涉及的主要視圖
直方圖類型的視圖:DBA_TAB_COL_STATISTICS,USER_TAB_COL_STATISTICS,ALL_TAB_COL_STATISTICS
直方圖具體信息的視圖:DBA_TAB_HISTOGRAMS,USER_TAB_HISTOGRAMS,ALL_TAB_HISTOGRAMS
6、直方圖對於執行計劃選擇影響的示例說明
本示例中使用的資料庫版本為ORACLE 11.2.0.4。
首先,準備一張測試表TEST,其中OWNER列存在嚴重的數據傾斜,具體如下。
Yumiko_sunny@OA01> select distinct owner ,count(*) as col_rows, 2 (select count(*) from test) as tab_rows, 3 to_char(round(count(*)/(select count(*) from test)*100,2),'90.99')||'%' 4 as data_ratio 5 from test group by owner; OWNER COL_ROWS TAB_ROWS DATA_RATIO -------------------- ---------- ---------- ---------- HR 476 535164 0.09% OE 1988 535164 0.37% ORDDATA 3598 535164 0.67% SCOTT 98 535164 0.02% SYS 529004 535164 98.85%
從上圖中可以看到,該列的SYS值分佈占到了整體的98%,表明存在嚴重的傾斜。
為OWNER列創建索引,並使用ANALYZE TABLE的方法收集統計信息。
--收集統計信息
Yumiko_sunny@OA01> analyze table test compute statistics; Table analyzed.
--驗證最後的統計收集的時間 Yumiko_sunny@OA01> select table_name, 2 to_char(LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 3 from dba_tables where TABLE_NAME='TEST'; TABLE_NAME LAST_ANALYZED ------------------------------ ------------------- TEST 2016-11-13 21:23:19 --查看直方圖的統計情況 Yumiko_sunny@OA01> select column_name,histogram from dba_tab_col_statistics where table_name='TEST'; COLUMN_NAME HISTOGRAM -------------------- --------------- OWNER NONE OBJECT_NAME NONE SUBOBJECT_NAME NONE OBJECT_ID NONE DATA_OBJECT_ID NONE OBJECT_TYPE NONE CREATED NONE LAST_DDL_TIME NONE TIMESTAMP NONE STATUS NONE TEMPORARY NONE COLUMN_NAME HISTOGRAM -------------------- --------------- GENERATED NONE SECONDARY NONE NAMESPACE NONE EDITION_NAME NONE
在上面的方法中,雖然通過analyze table table_name compute statistics的方法,收集了表的統計信息,但並未收集直方圖的信息。
這裡先忽略,後面可以對比for all columns子句的情況再看下。
查看此時索引列執行計劃的選擇情況,這裡以傾斜數據SYS為條件進行檢索。
Yumiko_sunny@OA01> select * from test where owner='SYS'; 529004 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3856466897 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 107K| 10M| 1799 (1)| 00:00:22 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 107K| 10M| 1799 (1)| 00:00:22 | |* 2 | INDEX RANGE SCAN | IND_TEST | 107K| | 228 (1)| 00:00:03 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OWNER"='SYS')
從上面返回的結果看,529K行的SYS數據,僅僅返回107K行,顯然存在很大的誤差。
此外,對於數據傾斜達到98%的SYS而言,顯然全表掃描的效率應該更高,這裡應該與錯誤的統計信息有關。
使用dbms_stats.gather_table_stats的方式再次收集表的統計信息。
Yumiko_sunny@OA01> exec dbms_stats.gather_table_stats('SCOTT','TEST',cascade=>true); PL/SQL procedure successfully completed. Yumiko_sunny@OA01> select table_name, 2 to_char(LAST_ANALYZED,'YYYY-MM-DD HH24:MI:SS') LAST_ANALYZED 3 from dba_tables where TABLE_NAME='TEST'; TABLE_NAME LAST_ANALYZED ------------------------------ ------------------- TEST 2016-11-13 21:50:01 Yumiko_sunny@OA01> select column_name,histogram from dba_tab_col_statistics where table_name='TEST'; COLUMN_NAME HISTOGRAM -------------------- --------------- OWNER FREQUENCY OBJECT_NAME NONE SUBOBJECT_NAME NONE OBJECT_ID NONE DATA_OBJECT_ID NONE OBJECT_TYPE NONE CREATED NONE LAST_DDL_TIME NONE TIMESTAMP NONE STATUS NONE TEMPORARY NONE COLUMN_NAME HISTOGRAM -------------------- --------------- GENERATED NONE SECONDARY NONE NAMESPACE NONE EDITION_NAME NONE
從上圖可以看到,此時完成了對錶的最新統計,同時收集了索引列的直方圖信息,且該直方圖為”等頻直方圖“。
再次查看此時索引列的執行計劃選擇情況,這裡分別以選擇性差的傾斜數據SYS為條件,以及以選擇性好的SCOTT為條件分別進行檢索。
--以SYS為條件進行查詢
Yumiko_sunny@OA01> select * from test where owner='SYS'; 529004 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1357081020 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 530K| 49M| 2098 (1)| 00:00:26 | |* 1 | TABLE ACCESS FULL| TEST | 530K| 49M| 2098 (1)| 00:00:26 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("OWNER"='SYS')
--以SCOTT為條件進行查詢 Yumiko_sunny@OA01> select * from test where owner='SCOTT'; 98 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3856466897 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 98 | 9506 | 5 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 98 | 9506 | 5 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IND_TEST | 98 | | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OWNER"='SCOTT')
如之前所說,通過直方圖收集準確的數據分佈信息,
對於選擇性差的SYS值,CBO優化器採用了全表掃描的方式進行數據的訪問
對於選擇性好的SCOTT值,CBO優化器則採用了索引掃描的方式進行數據的訪問
如果採用索引的方式訪問SYS相關的數據行,真實的代價會是怎樣呢,這裡,通過hint的方式進行一次索引掃描的訪問
Yumiko_sunny@OA01> select /*+index(test,ind_test) */* from test where owner='SYS'; 529004 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3856466897 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 529K| 49M| 8885 (1)| 00:01:47 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST | 529K| 49M| 8885 (1)| 00:01:47 | |* 2 | INDEX RANGE SCAN | IND_TEST | 529K| | 1115 (1)| 00:00:14 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OWNER"='SYS')
從上圖中可以看到,在信息收集無誤的情況下,若採用索引掃描,其真實開銷是全表掃描的4倍。
通過上面這個執行計劃,也說明瞭,對於CBO優化器,準確無誤的統計信息對於執行計劃選擇的重要性。
通過DBA_TAB_HISTOGRAMS視圖,查看此時直方圖的詳細信息
Yumiko_sunny@OA01> select TABLE_NAME,COLUMN_NAME,ENDPOINT_NUMBER, 2 to_char(ENDPOINT_VALUE,'999999999999999999999999999999999999') 3 as ENDPOINT_VALUE,ENDPOINT_ACTUAL_VALUE 4 from DBA_TAB_HISTOGRAMS 5 where TABLE_NAME='TEST' and COLUMN_NAME='OWNER'; TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALU ---------------------------------------------------------------------------------------- TEST OWNER 19 41159093808690300000000000 TEST OWNER 61 41186001805076000000000000 TEST OWNER 62 43232584582496500000000000 TEST OWNER 5 37550853140200700000000000 TEST OWNER 5518 43277234965060400000000000
可以看到,雖然ENDPOINT_VALUE收集到了唯OWNER列唯一值的hash值,但真實列ENDPOINT_ACTUAL_VALUE顯示為空。
後面對比analyze table for all columns操作後再看。
刪除SYS值相關的數據行,觀察直方圖統計的變化
Yumiko_sunny@OA01> delete from test where owner='SYS'; 529004 rows deleted. Yumiko_sunny@OA01> commit; Commit complete. Yumiko_sunny@OA01> select TABLE_NAME,COLUMN_NAME,ENDPOINT_NUMBER, 2 to_char(ENDPOINT_VALUE,'999999999999999999999999999999999999') 3 as ENDPOINT_VALUE,ENDPOINT_ACTUAL_VALUE 4 from DBA_TAB_HISTOGRAMS 5 where TABLE_NAME='TEST' and COLUMN_NAME='OWNER';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALU ---------------------------------------------------------------------------------------- TEST OWNER 19 41159093808690300000000000 TEST OWNER 61 41186001805076000000000000 TEST OWNER 62 43232584582496500000000000 TEST OWNER 5 37550853140200700000000000 TEST OWNER 5518 43277234965060400000000000
可以看到,對錶數據的DML操作,直方圖信息並未自動更改。
再次使用dbms_stats.gather_table_stats收集統計信息,此時直方圖得到了更新,如下圖:
Yumiko_sunny@OA01> exec dbms_stats.gather_table_stats('SCOTT','TEST',cascade=>true);
PL/SQL procedure successfully completed.
Yumiko_sunny@OA01> select TABLE_NAME,COLUMN_NAME,ENDPOINT_NUMBER,
2 to_char(ENDPOINT_VALUE,'999999999999999999999999999999999999')
3 as ENDPOINT_VALUE,ENDPOINT_ACTUAL_VALUE
4 from DBA_TAB_HISTOGRAMS
5 where TABLE_NAME='TEST' and COLUMN_NAME='OWNER';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALU
-------------------- ---------------------------- ---------------------------------------
TEST OWNER 476 37550853140200700000000000
TEST OWNER 2464 41159093808690300000000000
TEST OWNER 6062 41186001805076000000000000
TEST OWNER 6160 43232584582496500000000000
上述說明瞭,對於直方圖的信息,需要定期進行收集工作。
7、ANALYZE TABLE操作對直方圖統計影響的示例說明
本示例承接上面示例內容,資料庫版本一致。
在上面內容中,已經演示了analyze table table_name compute statistics無法針對錶進行直方圖的信息收集。
那麼,對於已存在直方圖的表,該操作又會有何影響呢。
首先,承接上面內容,再次執行analyze table table_name compute statistics的操作,觀察直方圖信息的變化。
Yumiko_sunny@OA01> analyze table test compute statistics; Table analyzed. Yumiko_sunny@OA01> select column_name,histogram from dba_tab_col_statistics where table_name='TEST'; COLUMN_NAME HISTOGRAM -------------------- --------------- OWNER NONE OBJECT_NAME NONE SUBOBJECT_NAME NONE OBJECT_ID NONE DATA_OBJECT_ID NONE OBJECT_TYPE NONE CREATED NONE LAST_DDL_TIME NONE TIMESTAMP NONE STATUS NONE TEMPORARY NONE COLUMN_NAME HISTOGRAM -------------------- --------------- GENERATED NONE SECONDARY NONE NAMESPACE NONE EDITION_NAME NONE
可以明顯的發現,OWNER列的直方圖信息消失了,說明該操作會刪除已存在的直方圖信息。
如果這是一個生產環境,對於這樣一張存在數據傾斜列的表,可能會帶來不可預估的影響。
對於analyze table table_name compute statistics for all indexes的操作,這裡不再演示,會在下麵的總結中,直接給出對直方圖影響的結論。
下麵看一下analyze table table_name compute statistics for all indexes for all columns操作的影響。
Yumiko_sunny@OA01> analyze table test compute statistics for all indexes for all columns;
Table analyzed.
Yumiko_sunny@OA01> select column_name,histogram from dba_tab_col_statistics where table_name='TEST';
COLUMN_NAME HISTOGRAM
-------------------- ---------------
OWNER FREQUENCY
OBJECT_NAME HEIGHT BALANCED
SUBOBJECT_NAME NONE
OBJECT_ID HEIGHT BALANCED
DATA_OBJECT_ID HEIGHT BALANCED
OBJECT_TYPE FREQUENCY
CREATED FREQUENCY
LAST_DDL_TIME FREQUENCY
TIMESTAMP FREQUENCY
STATUS FREQUENCY
TEMPORARY FREQUENCY
COLUMN_NAME HISTOGRAM
-------------------- ---------------
GENERATED FREQUENCY
SECONDARY FREQUENCY
NAMESPACE FREQUENCY
EDITION_NAME NONE
從上面可以看到,當執行for all columns子句的時候,不但收集了索引列的直方圖信息,還收集了非索引列的直方圖信息。
再看下此時DBA_TAB_HISTOGRAMS視圖的詳細信息
Yumiko_sunny@OA01> select TABLE_NAME,COLUMN_NAME,ENDPOINT_NUMBER,
2 to_char(ENDPOINT_VALUE,'999999999999999999999999999999999999')
3 as ENDPOINT_VALUE,ENDPOINT_ACTUAL_VALUE
4 from DBA_TAB_HISTOGRAMS
5 where TABLE_NAME='TEST' and COLUMN_NAME='OWNER';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALU
-------------------- ---------------------------- ---------------------------------------
TEST OWNER 476 37550853140200700000000000 HR
TEST OWNER 2464 41159093808690300000000000 OE
TEST OWNER 6062 41186001805076000000000000 ORDDATA
TEST OWNER 6160 43232584582496500000000000 SCOTT
可以看到,此時可以看見DBA_TAB_HISTOGRAMS視圖上,ENDPOINT_ACTUAL_VALUE列真實值的信息。
8、總結
- 直方圖可以為CBO優化器提供準確的數據分佈參考,以便選擇正確的執行計劃。
- 預設情況下,使用dbms_stats.gather_table_stats得到的直方圖信息,只會收集索引列的直方圖信息。
- 預設情況下,使用dbms_stats.gather_table_stats得到的直方圖信息,無法在DBA_TAB_HISTOGRAMS視圖中看到真實值,但不影響CBO優化器的選擇。
- 使用analyze table table_name compute statistics進行統計分析,對於尚未存在直方圖信息的表,不會收集直方圖信息。
- 使用analyze table table_name compute statistics進行統計分析,對於已經存在直方圖信息的表,會刪除之前的直方圖信息。
- 使用analyze table table_name compute statistics for all indexes進行統計分析,對於尚未存在直方圖信息的表,不會收集直方圖信息。
- 使用analyze table table_name compute statistics for all indexes進行統計分析,對於已經存在直方圖信息的表,不會刪除之前的直方圖信息。
- 使用analyze table table_name compute statistics for all indexes for all columns進行統計分析,對於尚未存在直方圖信息的表,會收集直方圖信息,且包括索引列以及非索引列。
- 使用analyze table table_name compute statistics for all indexes for all columns進行統計分析,對於已經存在直方圖信息的表,會收集最新的直方圖信息。
最後一點,起碼從直方圖的收集情況看:analyze table table_name compute statistics並不等價於analyze table table_name compute statistics for all indexes for all columns
謹慎使用analyze table table_name compute statistics這個操作。
重要的事情說三遍!!!