㈠ Histograms
柱狀圖?長條圖?其實這倆是一個概念,在這裡Think直接用histograms來稱呼
histograms可以這麼理解就是一個列上數值的大致分布的密度(density)和範圍(range)
通俗一些就是CBO用histgrams來更加準確的判斷按照某個條件對每一列查詢能返回多少記錄
histograms有兩種類型
① 基於高度的histograms:每個範圍包括相同數量的值,根據每個範圍的終點的列值來判斷資料的分布
② 基於數值的histograms:當列中不同的值的數量少於或等於histograms的buckets數量時,建立數值histograms
這種histograms列中每個值都有對應的bucket,根據每個值對應的bucket的個數來判斷資料的分布
我們可以從視圖dba_histograms/user_histograms,dba_tab_histograms查詢
① 為什麼需要histograms?
我們對經常在WHERE子句中使用的且資料的分布十分不均勻的列使用histograms
長條圖究其根本實際上就是一個資料分布的圖示,這個圖示是為了在產生SQL執行計畫的時候給Oracle的CBO更多的資訊
也就是說,當在where條件中的某些列可能由於列值的不同而希望CBO制定出不同的執行計畫時,我們需要長條圖
那麼,什麼情況下我們不需要長條圖呢?
⑴ 當此列不用於查詢時,也就是這個欄位永遠不會出現在where條件中
⑵ 當此列無論給予什麼比較值,我們都希望永遠是一種執行計畫時,比如,col1我們希望永遠是用該列上的索引掃描
col2我們希望永遠是全表掃描,這樣的執行計畫的制定,只要有表層級的統計資訊就足夠了
長條圖資訊的出現不但不會對制定正確的執行計畫有協助,甚至會出現奇怪的現象導致執行計畫不穩定
⑶ 列中資料均勻分布,比如社會安全號碼,QQ號,主鍵等
⑷ 列中資料唯一且只使用相等作為判定條件
⑸ 對這個列所有的判定條件都使用了綁定變數
② 如何搜集histograms
只有我們的DBA才最知道哪些列上應該收集長條圖,這實際上已經遠遠不僅僅是技術問題了
而是一個業務問題,因此DBA應該去熟悉業務,DBA應該知道自己的應用的資料分布特點,應該知道哪些列會常被用在where條件中
Ⅰ analyze
histograms事實上它描述的就是資料在儲存桶的分布範圍!
如何產生histograms?可以通過對錶做分析!
analyze table table_name compute statistics:不僅分析了表和索引,而且分析了表上的所有列,並產生了列的histograms
analyze table table_name compute statistics for table:僅僅產生表的statistics,不產生列的histograms
analyze table table_name compute statistics for all indexed columns:分析了表,並僅對錶上的索引列產生histograms
analyze table table_name compute statistics for all columns:分析表,同時產生所有列的histograms
對所有列都產生histograms是沒有意義的,只有對where語句中用到的列產生histograms是有意義的
預設列的histograms只有一個桶,可以對列分析時指定多個桶:
analyze table table_name compute statistics for columns column_name size n;
Ⅱ dbms_stats.gather_table_stats
⒈ 第一次收集統計資訊時,設定method_opt=>FOR ALL COLUMNS SIZE 1,這意味刪除所有列上的長條圖
⒉ 在測試階段或者在真實生產環境中,在調優SQL的過程中,DBA將會逐漸得知每個需要長條圖資訊的欄位
在這些欄位上人工收集統計資訊,method_opt=>FOR COLUMNS SIZE AUTO [COLUMN_NAME]
如果你能夠明確知道應該收集多少個bucket而手工指定SIZE值那更好。保留收集所有這些欄位的指令碼
以備資料庫系統升級或者遷移時候使用
⒊ 在每次資料分布有所變化的時候,更新統計資料,使用method_opt=>FOR ALL COLUMNS SIZE REPEAT
這樣只會收集已經存在了長條圖資訊的欄位
重複2,3步驟,直到系統穩定。這是一個可控的步驟,只有可控,才可能避免不可預知的錯誤
㈡ skew
Oracle在界定skew時並不是用重複值來判斷的
Oracle認為的傾斜列是指在最大值和最小值之間分布不均勻,即使它是唯一的
測試:
SQL> create table numa as select rownum a from histest;Table createdExecuted in 3.938 secondsSQL> select count(*) from numa; COUNT(*)---------- 1024384Executed in 0.297 secondsSQL> delete from numa where a between 9999 and 1024383;1014382 rows deletedExecuted in 73.86 secondsSQL> commit;Commit completeExecuted in 0 secondsSQL> select count(*) from numa; COUNT(*)---------- 10001Executed in 0.187 secondsSQL> alter table NUMA 2 add constraint UK_NUMA unique (A);Table alteredExecuted in 0.219 secondsSQL> exec dbms_stats.gather_table_stats(ownname => 'MYDB',tabname => 'NUMA',method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY');PL/SQL procedure successfully completedExecuted in 0.328 secondsSQL> SELECT COUNT(*), column_name 2 FROM dba_tab_histograms 3 WHERE table_name = 'NUMA' 4 AND column_name = 'A' 5 GROUP BY column_name 6 ORDER BY column_name DESC 7 / COUNT(*) COLUMN_NAME---------- -------------------------------------------------------------------------------- 201 AExecuted in 0.078 seconds