Oracle优化07-分析及动态采样-直方图
思維導圖
07系列文章
Oracle優化07-分析及動態采樣-直方圖
Oracle優化07-分析及動態采樣-DBMS_STATS 包
Oracle優化07-分析及動態采樣-動態采樣
概述
獲取準確的段對象(表、表分區、索引等)的分析數據,是CBO存在的基石。所以數據段的分析對于CBO來講非常的重要。
在本篇博文中我們重新梳理一下,從頭開始,再一次走進CBO的世界。
我們知道CBO的機制是手機盡可能多的對象信息和系統信息,通過對這些信息進行計算、分析、評估,最終得出一個成本最低的執行花來,這就是CBO的全部。 為了讓CBO總是能做出最正確的SQL執行計劃,就需要給CBO提供盡可能多的信息。
舉個簡單的例子:
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 Connected as xxx@xgj##通過 1=2 不成立的條件,創建一個空表(后續建索引會快一點兒) SQL> create table t as select object_id ,object_name from dba_objects where 1=2;Table created##創建索引 SQL> create index ind_t on t(object_id);Index created##插入數據 SQL> insert into t select object_id ,object_name from dba_objects;35260 rows insertedSQL> commit;Commit complete## 沒有對表進行分析,可以通過下面兩個視圖來確認 SQL> select a.NUM_ROWS,a.AVG_ROW_LEN ,a.BLOCKS,a.LAST_ANALYZED from user_tables a where a.TABLE_NAME='T';NUM_ROWS AVG_ROW_LEN BLOCKS LAST_ANALYZED ---------- ----------- ---------- -------------SQL> select a.blevel ,a.leaf_blocks ,a.distinct_keys,a.last_analyzed from user_indexes a where a.table_name='T';BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED ---------- ----------- ------------- -------------0 0 0 2017-01-08 11SQL>表的行數、行長、占用的數據塊數以及最后分析時間都是空的,索引的相關信息也都為0,說明這個表和索引都沒有被分析過。
如果此時又一條SQL對表做查詢,CBO由于無法獲取這些信息,很可能生成錯誤的執行計劃。如下所示:
查看SQL的執行計劃:
執行SQL SQL> select /*+ dynamic_sampling(t 0) */ * from t where t.object_id>30; ...省略輸出 SQL> select a.SQL_ID,a.CHILD_NUMBER from v$sql a where a.SQL_TEXT like 'select /*+ dynamic_sampling(t 0) */ * from t where t.object_id>30%';SQL_ID CHILD_NUMBER ------------- ------------ f5q92sydyqc4z 0##查看執行計劃 SQL> select * from table(dbms_xplan.display_cursor('f5q92sydyqc4z',0));PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID f5q92sydyqc4z, child number 0 ------------------------------------- select /*+ dynamic_sampling(t 0) */ * from t where t.object_id>30 Plan hash value: 4013845416 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 (100)| | 1 | TABLE ACCESS BY INDEX ROWID| T | 4 | 316 | 0 (0)| |* 2 | INDEX RANGE SCAN | IND_T | 1 | | 0 (0)| -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("T"."OBJECT_ID">30)10g以后,如果一個表沒有做過分析,ORACLE會自動對它做動態采用分析, 我們使用/+ dynamic_sampling(t 0) /這種Hint 將動態采樣的級別設置為0,即不使用動態采樣.
CBO估算出滿足條件的記錄為4條,所以選擇了索引。 實際情況呢? 我們先對表做個分析操作。
9i開始,Oracle推薦使用DBMS_STATS包對表進行分析操作。
為CBO收集信息
SQL> exec dbms_stats.gather_table_stats(user,'t');PL/SQL procedure successfully completedSQL> select a.NUM_ROWS,a.AVG_ROW_LEN ,a.BLOCKS,a.LAST_ANALYZED from user_tables a where a.TABLE_NAME='T';NUM_ROWS AVG_ROW_LEN BLOCKS LAST_ANALYZED ---------- ----------- ---------- -------------35260 24 244 2017-01-08 14SQL> select a.blevel ,a.leaf_blocks ,a.distinct_keys,a.last_analyzed from user_indexes a where a.table_name='T';BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED ---------- ----------- ------------- -------------1 98 35257 2017-01-08 14SQL>dbms_stats.gather_table_stats(user,’t’)默認對表和索引都進行了分析.
清掉shared_pool 重新看下執行計劃。
## 清掉 shared_pol SQL> alter system flush shared_pool;System alteredSQL> select * from t where t.object_id>30; 省略輸出...SQL> select a.SQL_ID,a.CHILD_NUMBER from v$sql a where a.SQL_TEXT like 'select * from t where t.object_id>30%';SQL_ID CHILD_NUMBER ------------- ------------ fcvjyr3skfj5b 0SQL> select * from table(dbms_xplan.display_cursor('fcvjyr3skfj5b',0));PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID fcvjyr3skfj5b, child number 0 ------------------------------------- select * from t where t.object_id>30 Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 68 (100)| | |* 1 | TABLE ACCESS FULL| T | 35234 | 825K| 68 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------1 - filter("T"."OBJECT_ID">30)SQL>我們看到T表在做完分析后,CBO估算出的結果集為35234 ,和實際情況相差很小。
所以使用全表掃描更優。 因為這種情況下,如果先訪問索引,然后根據索引的鍵值去尋找表的記錄,勢必會導致讀取更多的數據塊,走全表反而會更快一些。
直方圖 Histogram
直方圖 (Histogram), 是數據分析分析當中的一個內容,但它對CBO的影響非常大。
DBMS_STATS 包對段表的分析有三個層次:
我們現在說的直方圖,單指第二項的最后一種 列分析中 數據在列上的分布情況。
當 Oracle 做直方圖分析時,會將要分析的列上的數據分成很多數量相同的部分,每一部分稱為一個 bucket,這樣 CBO 就可以非常容易地知道這個列上的數的分布情況,這種數據的分布將作為一個非常重要的因素納入到執行計劃成本的計算當中。
對于數據分部非常傾斜的表,做直方圖分析是非常有用的。
來看下面兩個例子:
圖一的數據分布非常均勻的直方圖模式,每一個數值范圍(bucket)內的數據記錄都基本上一樣。
圖二,數據分部嚴重傾斜,數值小于20的記錄占到了總記錄的70%。
直方圖有時候對于CBO非常的重要,特別是對于字段數據非常傾斜的表,做直方圖分析尤為重要。
舉例說明:
SQL> create table t as select 1 id ,object_name from dba_objects;Table createdSQL> update t set t.id=99 where rownum=1;1 row updatedSQL> commit;Commit completeSQL> create index ind_t on t(id);Index created##查看數據分布情況 SQL> select id ,count(1) from t group by id;ID COUNT(1) ---------- ----------1 3525699 1 ## 表和索引分析 SQL> exec dbms_stats.gather_table_stats(user,'t',cascade=>true);PL/SQL procedure successfully completedSQL>查看分析后的情況:
SQL> select a.num_rows,a.avg_row_len ,a.blocks,a.last_analyzed from user_tables a where a.table_name='T';NUM_ROWS AVG_ROW_LEN BLOCKS LAST_ANALYZED ---------- ----------- ---------- -------------35257 22 144 2017-01-08 18 SQL> select a.blevel ,a.leaf_blocks ,a.distinct_keys,a.last_analyzed from user_indexes a where a.table_name='T';BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED ---------- ----------- ------------- -------------1 69 2 2017-01-08 18SQL>DISTINCT_KEYS : 2
我們創建了一張表,id字段傾斜非常嚴重,除了一條id=99的數據之外,其余的id全部為1。
默認情況下,dbms_stats包會對所有的列做直方圖分析。
查看直方圖的信息視圖 user_histogram
SQL> select * from user_histograms a where a.TABLE_NAME = 'T' ;查看如下SQL的執行計劃
select * from t where id=1; select * from t where id=99;現在我們將直方圖信息刪除,但是保留表和索引的分析信息
SQL> exec dbms_stats.delete_column_stats(user,'t',colname => 'id');PL/SQL procedure successfully completed再此查看T表直方圖的視圖信息
我們可以看到ID字段的信息已經被刪除掉了。
查看表和索引的信息
我們可知索引和表的信息依然存在,并且索引中甚至可以找到distinct_keys=2。但是CBO卻無法得到這兩個數值的分布情況,所以依然沒法選出一個正確的執行計劃。
下面看實例:
select * from t where id=1;
select * from t where id=99;
CBO在id =1 時,估算返回的結果是353行,比較全部表的記錄35257(這個信息可以從表的分析數據中得到user_tables.NUM_ROWS字段), CBO認為選擇索引是合適的,但是我們知道實際上id=1的記錄數基本上等于表的全部記錄。在這種情況下CBO沒法得到數據的具體分布情況,所以做出了錯誤的執行計劃
同樣的CBO在id=99的情況下,CBO估算出返回值是6條。
因此我們可以斷定,如果一個裂傷的數據有比較嚴重的傾斜,對這個列做直方圖是有必要的。
那是不是每個表的每個列都應該做直方圖分析呢?
其實是一個沒有定論的話題。因為首先要知道,Oracle對數據分析是需要消耗資源的,特別是對于一些很大的段對象,分析的時間尤其長。 所以權衡一下,既要避免分析導致系統性能下降而對業務產生影響,同時又要保證CBO獲取足夠的信息來產生正確的執行計劃。
總結
以上是生活随笔為你收集整理的Oracle优化07-分析及动态采样-直方图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle优化05-执行计划
- 下一篇: Oracle优化08-并行执行