cbo心得(選擇率,基數,直方圖)(三)
SQL> drop table sunwg purge;
表已刪除。
SQL> create table sunwg (id number);
表已建立。
SQL> create index ind_sunwg on sunwg(id);
索引已建立。
SQL> insert into sunwg select 1 from dba_objects where rownum<2001;
已建立2000行。
SQL> insert into sunwg select 1+ rownum from dba_objects where rownum<2001;
已建立2000行。
SQL> commit;
提交完成。
SQL> analyze table sunwg compute statistics for table for all indexes for columns id size 1;
表已分析。
這樣我們就有了一個有傾斜列的表SUNWG,在表中id = 1的記錄有2000條,佔了全部記錄的50%。查詢下表和索引的統計資訊,看看我們都告訴了CBO什麼資訊。
SQL> select NUM_ROWS,
2 BLOCKS,
3 EMPTY_BLOCKS,
4 AVG_SPACE,
5 CHAIN_CNT,
6 AVG_ROW_LEN
7 from user_tables
8 where table_name = 'SUNWG';
NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN
---------- ---------- ------------ ---------- ---------- -----------
4000 13 3 4687 0 6
SQL> select BLEVEL,
2 LEAF_BLOCKS,
3 DISTINCT_KEYS,
4 AVG_LEAF_BLOCKS_PER_KEY,
5 AVG_DATA_BLOCKS_PER_KEY,
6 CLUSTERING_FACTOR
7 from user_indexes
8 where index_name = 'IND_SUNWG';
BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY
---------- ----------- ------------- -----------------------
AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
----------------------- -----------------
1 8 2001 1
1 7
SQL> select NUM_DISTINCT,
2 LOW_VALUE,
3 HIGH_VALUE,
4 DENSITY,
5 NUM_NULLS,
6 NUM_BUCKETS,
7 HISTOGRAM
8 from user_tab_columns
9 where table_name ='SUNWG'
10 and column_name = 'ID';
NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS NUM_BUCKETS HISTOGRAM
----------- --------- --------- ------ -------- ----------- --------
2001 C102 C21502 .00049975 0 1 NONE
關於LOW_VALUE和HIGH_VALUE要特別說明下,在user_tab_columns裡面的這兩個值是採用RAW資料型別來儲存的。我們想要得到number型別的值需要呼叫dbms_stats中的過程convert_raw_value。下面是個寫好函式raw_to_number。
function raw_to_number (in_raw raw)
return number
as
ft FLOAT(126);
begin
dbms_stats.convert_raw_value(in_raw,ft);
return ft;
end;
SQL> select * from sunwg where id = 50;
執行計劃
----------------------------------------------------------
Plan hash value: 3109917279
---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2 | 6 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| IND_SUNWG | 2 | 6 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID"=50)
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
402 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
上面這條SQL,CBO選擇的透過索引範圍掃描來執行。CBO為什麼會做出這樣的決定呢?我們看一下計劃裡面有一列是Rows,這列代表著ORACLE估計的結果集合的大小。前面這個例子中ORACLE估計ID = 50的結果集大概是2條。實際上呢,ID = 50的記錄只有一條。先不管這點差異,在總量是4000條記錄的表中查詢幾條記錄用索引掃描會更加的高效。因此,CBO選擇了索引掃描而不採用全表掃描。
接下來在說這個Rows = 2是怎麼產生的。在列的統計資訊中一個欄位是NUM_DISTINCT,它說明該列不同值的個數。由於不存在直方圖資訊,ORACLE無法知道列上資料的真實分佈情況,所以ORACLE假設資料在列ID上是平均分配的。所以ID = 50的記錄數就應該是:
4000 * (1/2001) = 1.99
SQL> select * from sunwg where id = 1;
已選擇2000行。
執行計劃
----------------------------------------------------------
Plan hash value: 3109917279
---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2 | 6 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| IND_SUNWG | 2 | 6 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID"=1)
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
138 consistent gets
0 physical reads
0 redo size
27319 bytes sent via SQL*Net to client
1848 bytes received via SQL*Net from client
135 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2000 rows processed
上面的這個例子中ORACLE關於結果集的估計是差得比較多了,實際上ID = 1的記錄有2000條,可ORACLE的估計值只有2條。差距這麼大的就可能導致CBO選擇錯誤的執行計劃,用低效的索引掃描來代替更加高效的全表掃描。直方圖資訊就是用來解決這種問題的,在資料傾斜的情況下給ORACLE更多的資訊,使ORACLE可以意識到傾斜的存在。
我們上邊僅僅對ID = 1這樣的最簡單的情況進行了測試,平時常用的謂詞還有>,>=,<等等,下表列出了常用的一些謂詞的情況
Where 條件 | Oracle估計記錄數 | 表中實際記錄數 | Oracle估算公式(猜想) |
ID = 1 | 2 | 2000 | 4000 * (1/2001) |
ID > 1 | 3998 | 2000 | 4000 * (2001 – 1)/2001 |
ID >= 1 | 4000 | 4000 | 4000*(2001 – 1/2001)+2 |
ID = 110 | 2 | 0 | 1<= X<= 4000 * (1/2001) |
ID + 1 > 1 | 200 | 4000 | 4000* 5% |
ID + 1 >= 1 | 200 | 4000 | 4000* 5% |
ID + 1 > 1 AND ID + 1 > 1 | 200 | 4000 | 4000* 5% |
ID > 1 AND ID < 50 | 96 | 48 | 4000 *( 5%* 5%) - 2 - 2 |
ID >= 1 AND ID <= 50 | 100 | 2049 | 4000 *( 5%* 5%) |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9533994/viewspace-1008779/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【cbo計算公式】Frequenccy 直方圖選擇率(三)公式直方圖
- 【cbo計算公式】Height-balance直方圖選擇率(四)公式直方圖
- CBO計算與資料型別的選擇(兼談日期、字元、數字三種型別的直方圖生成原理和使用)資料型別字元直方圖
- 【cbo計算公式】Join 選擇率(六)公式
- 【cbo計算公式】單表選擇率(二)公式
- 數字影像處理讀書筆記(三)直方圖匹配筆記直方圖
- 深度學習(模型引數直方圖)深度學習模型直方圖
- 直方圖均衡化直方圖
- 直方圖學習直方圖
- python如何畫直方圖Python直方圖
- halcon-直方圖均衡直方圖
- 直方圖中最大矩形直方圖
- [Python影象處理] 十一.灰度直方圖概念及OpenCV繪製直方圖Python直方圖OpenCV
- OpenCV計算機視覺學習(9)——影像直方圖 & 直方圖均衡化OpenCV計算機視覺直方圖
- 三方對接「心得」與「體會」
- elasticsearch 之 histogram 直方圖聚合ElasticsearchHistogram直方圖
- Matplotlib直方圖繪製技巧直方圖
- 【影像處理】基於OpenCV實現影像直方圖的原理OpenCV直方圖
- 【16位RAW影像處理三】直方圖均衡化及區域性直方圖均衡用於16點陣圖像的細節增強。直方圖
- 第三方軟體測試機構如何選擇?
- 聊一聊MySQL的直方圖MySql直方圖
- [20221227]Adaptive Cursor Sharing & 直方圖.txtAPT直方圖
- 淺析MySQL 8.0直方圖原理MySql直方圖
- 一文搞懂直方圖均衡直方圖
- opencv——影像直方圖與反向投影OpenCV直方圖
- 【沃趣科技】直方圖系列1直方圖
- 你知道直方圖都能幹啥?直方圖
- OpenCV之影象直方圖均衡化OpenCV直方圖
- [數字影像學筆記] 4.直方圖變換2筆記直方圖
- 柱狀圖、直方圖、散點圖、餅圖講解直方圖
- 中科三方:SSL證書有哪些型別?如何去選擇?型別
- 直方圖均衡化原理與實現直方圖
- 一文搞懂 Prometheus 的直方圖Prometheus直方圖
- 灰度直方圖均衡化及其實現直方圖
- matplotlib的直方圖繪製(筆記)直方圖筆記
- Python 影像處理 OpenCV (16):影像直方圖PythonOpenCV直方圖
- [20190630]如何確定直方圖型別.txt直方圖型別
- 【R語言】繪製權重直方圖R語言直方圖
- HC(Histogram-based Contrast) 基於直方圖對比度的顯著性HistogramAST直方圖