Cardinality的計算
在資料庫中如果我們使用CBO作為優化器,那麼一條SQl語句的執行就會有多種執行路徑,但是有一點需要注意,CBO會計算各個執行路徑的訪問代價,從而選擇代價最小的執行路徑作為我們的執行計劃。通過10053事件可以trace出這樣的一個過程。那麼CBO在做訪問路徑估算的時候有一個很重要的引數作為我們計算Cost的因數,這個就是我們通常所說的掃描欄位的集的勢(Cardinality).關於這個值的計算比較的複雜,這裡我先討論一下使用繫結變數的情況下集的勢的計算。
一般公式如下:
Cardinality=MAX(Cardinality Factor * Rowcount,1)
那麼直接影響我們Cardinality結果的的其實就是Cardinality因子(Cardinality Factor).這個因子是怎麼計算的呢?來看一下在不同情況下的Cardinality Factor的計算
***********
索引欄位
***********
如果我們在欄位上面建立了索引,或者是對多個欄位建立了一個複合索引。這個索引欄位的計算方式有多種
對於這個欄位的查詢條件是"="的情況下,那麼我們的Cardinality Factor的計算公式就如下:
------------------------------------------------------------------------------------------------------------
Cardinality Factor = 1 / 欄位上的唯一值的數量
來看個例子:
C:\>sqlplus /nolog
SQL*Plus: Release 9.2.0.8.0 - Production on 星期二 1月 15 12:50:38 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
SQL> conn / as sysdba;
已連線。
SQL> create table t ( a number , b char(1), c char(5));
表已建立。
SQL> create index t_idx1 on t (b,c);
索引已建立。
SQL> begin
2 for i in 1 .. 1000 loop
3 insert into t values(i,mod(i,10),mod(i,13));
4 end loop;
5 commit;
6 end;
7 /
PL/SQL 過程已成功完成。
SQL> analyze table t compute statistics
2 for table
3 for all indexes
4 for all indexed columns;
表已分析。
SQL> select count(distinct b) from t;
COUNT(DISTINCTB)
----------------
10
SQL> select count(distinct c) from t;
COUNT(DISTINCTC)
----------------
13
SQL> select count(*) from
2 (select distinct b,c from t);
COUNT(*)
----------
130
我們來看看column b的cardinality
SQL> variable V char
SQL> exec :V := 8
PL/SQL 過程已成功完成。
SQL> set autotrace traceonly
SQL> select /*+index(t t_idx1)*/ * from t where b=:V;
已選擇100行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=41 Card=100 Bytes=15
00)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=41 Card=100 Byt
es=1500)
2 1 INDEX (RANGE SCAN) OF 'T_IDX1' (NON-UNIQUE) (Cost=2 Card
=100)
這裡我們可以看到索引的範圍掃描中 Card=100,
這個Cardinality的結果就是通過 round(1/10 * 1000) = 100,其中 1/10 這個10就是我們b列中唯一鍵的數量 得出的結果就是我們的集的式因子(Cardinality Factor)。需要注意的是(Cardinality Factor = 1/欄位上唯一值的數量)公式只適用於"="的情況下
我們來看看column c的cardinality
SQL> variable V char
SQL> exec :V := 3
PL/SQL 過程已成功完成。
SQL> select /*+index(t t_idx1)*/ * from t where c=:V;
已選擇77行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=35 Card=77 Bytes=115
5)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=35 Card=77 Byte
s=1155)
2 1 INDEX (FULL SCAN) OF 'T_IDX1' (NON-UNIQUE) (Cost=5 Card=
77)
這裡我們可以看到索引的全掃描中 Card=77,
這個Cardinality的結果就是通過 round(1/13 * 1000) = 100,其中 1/13 這個13就是我們c列中唯一鍵的數量 得出的結果就是我們的集的式因子(Cardinality Factor)。需要注意的是(Cardinality Factor = 1/欄位上唯一值的數量)公式只適用於"="的情況下
那麼如果索引欄位的查詢條件是"" "<=" ">=" 那麼我們計算Cardinality Factor的公式就為
------------------------------------------------------------------------------------------------------------
Cardinality Factor = (1 / 欄位上的唯一值的數量) + (1 / 記錄數)
比如:
SQL> select /*+index(t t_idx1)*/ * from t where b > :V;
已選擇600行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=101 Bytes=151
5)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=101 Bytes=1515)
這裡Cardnality就是等於[ (1/10) + (1/1000) ] * 1000 = 101
如果索引欄位的查詢條件是in,那麼我們的公式就為:
---------------------------------------------------------------------------
Cardinality Factor = in條件中的變數數 / 欄位上的唯一值的數量
比如:
SQL> variable A char
SQL> variable B char
SQL> variable C char
SQL> exec :A := 2
PL/SQL 過程已成功完成。
SQL> exec :B := 3
PL/SQL 過程已成功完成。
SQL> exec :C := 4
PL/SQL 過程已成功完成。
SQL> select /*+index(t t_idx10*/ * from t where b in (:A,:B,:C);
已選擇300行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=300 Bytes=450
0)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=300 Bytes=4500)
這裡我們可以看到全表掃描中 Card=300,
這個Cardinality的結果就是通過 round(3/10 * 1000) = 300,其中 3/10 這個3就是我們b列中in中的變數數得出的結果就是我們的集的式因子(Cardinality Factor)。
如果索引欄位的查詢條件是"<>",那麼我們的公式就為:
-----------------------------------------------------------------------------
Cardinality Factor = ( 1 - (1 / 欄位上的唯一值的數量 ) )
可以想想這是 "=" 的一個補集
比如
SQL> select /*+index(t t_idx1)*/ * from t where c <> :V;
已選擇923行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=365 Card=923 Bytes=1
3845)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=365 Card=923 By
tes=13845)
2 1 INDEX (FULL SCAN) OF 'T_IDX1' (NON-UNIQUE) (Cost=5 Card=
923)
在這裡我們可以看到索引的全掃描中 Card=923,
這個Cardinality的結果就是通過 round((1-1/13) * 1000) = 923,其中 1/13 這個13就是我們c列中唯一鍵的數量,其結果被1減去後得出的結果就是我們的集的式因子(Cardinality Factor)。
如果查詢條件為not in的時候,Cardinality的結果是根據not in中變數作為階乘得出的公式為:
------------------------------------------------------------------------------------------------------------
Cardinality Factor = ( 1 - (1 / 欄位上的唯一值的數量 ) ) ^ (not in 變數數)
SQL> select /*+index(t t_idx1)*/ * from t where b not in (:A,:B,:C);
已選擇700行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=290 Card=729 Bytes=1
0935)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=290 Card=729 By
tes=10935)
2 1 INDEX (FULL SCAN) OF 'T_IDX1' (NON-UNIQUE) (Cost=5 Card=
729)
在這裡我們可以看到索引的全掃描中 Card=729,
這個Cardinality的結果就是通過 round((1-1/10)^3 * 1000) = 729,其中 1/10 這個10就是我們b列中唯一鍵的數量,其結果被1減去後得出的結果,然後再^3,就是我們的集的式因子(Cardinality Factor)。
**************
非索引欄位
**************
當查詢條件為"="或者是"in"的時候,非索引欄位的Cardinality Factor的計算公式為:
-----------------------------------------------------------------------------------------------------------
Cardinality Factor = 1 / 100
比如:
SQL> select * from t where a = :V;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=10 Bytes=150)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=10 Bytes=150)
在這裡我們可以看到索引的全掃描中 Card=10,
這個Cardinality的結果就是通過 round((1/100) * 1000) = 10
當查詢條件為"","<=",">=","<>","not in",非索引欄位的Cardinality Factor的計算公式為:
-------------------------------------------------------------------------------------------------------------
Cardinality Factor = 1 / 20
比如:
SQL> select * from t where a >= :V;
已選擇991行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=50 Bytes=750)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=50 Bytes=750)
SQL> select * from t where a <= :V;
已選擇9行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=50 Bytes=750)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=50 Bytes=750)
SQL> select * from t where a <> :V;
已選擇999行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=50 Bytes=750)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=50 Bytes=750)
在這裡我們可以看到索引的全掃描中 Card=50,
這個Cardinality的結果就是通過 round((1/20) * 1000) = 50
********
多欄位
********
其公式只有一個就是:
Cardinality Factor = 欄位1的Cardinality Factor * 欄位2的Cardinality Factor * ... * 欄位n的Cardinality Factor
SQL> select /*+index(t t_idx1)*/ * from t where b > :V and c =:A;
已選擇46行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=6 Card=8 Bytes=120)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=6 Card=8 Bytes=
120)
2 1 INDEX (RANGE SCAN) OF 'T_IDX1' (NON-UNIQUE) (Cost=2 Card
=101)
首先我們看b>:v的Cardinality Factor = (1/10) + (1/1000)
c=:A的Cardinality Factor = (1/13)
所以這個cardinality factor的結果就是 = 0.101 * 0.0769 = 0.0077669
那麼Cardinality = round(0.0077669 * 1000) = 8
**********
全表掃描
**********
Cardinality Factor=1;
我們以下查詢的Cardinality的結果就為:
SQL> select * from t;
已選擇1000行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=2 Card=1000 Bytes=15
000)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=1000 Bytes=15000)
恩,就是1*1000=1000
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12361284/viewspace-145392/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 查詢計劃中集的勢(Cardinality)的計算
- DB優化小常識 - 執行計劃中Cardinality的計算優化
- CBO中基數(cardinality)、可選擇率(selectivity)的計算公式公式
- 使用繫結變數窺探後的cardinality和selectivity的計算方法變數
- 計算查詢條件是or區間時候的selectivity和Cardinality
- No_expand hint 解決CBO針對where...or..語句中的cardinality計算問題
- oracle中執行計劃中的cardinalityOracle
- Cardinality
- oracle cardinality對於執行計劃的影響Oracle
- 7.40 CARDINALITY
- oracle 查詢計劃中的基數cardinality概念(二)Oracle
- oracle 查詢計劃中的基數cardinality概念(一)Oracle
- 使用multicolumns statistics幫助Optimizer計算出更準確的cardinality
- MySQL InnoDB儲存引擎更新Cardinality統計資訊的策略介紹MySql儲存引擎
- Oracle Database Cardinality FeedbackOracleDatabase
- Cardinality指什麼?
- Cardinality (222)
- 雲端計算,網格計算,分散式計算,叢集計算的區別?分散式
- zt:Cardinality (SQL statements) 最好的解釋SQL
- 16.基數(Cardinality)
- CARDINALITY HINT用法小試
- 計算機計算小數除法的陷阱計算機
- 簡單解析MySQL中的cardinality異常MySql
- 高效的SQL(bitmap indexes optimize low cardinality columns)SQLIndex
- Are we ready for learned cardinality estimation?
- 基數反饋(Cardinality Feedback)
- 那些語句使用cardinality feedback
- Cardinality Feedback基數反饋
- 冪的計算
- 音量的計算
- 邊緣計算與雲端計算的未來
- 本地計算、雲端計算、霧計算、邊緣計算有什麼區別?
- word公式怎麼計算 word公式計算的方法公式
- 圖計算 on nLive:Nebula 的圖計算實踐
- Tableau的計算欄位、粒度、聚合、比率、表計算
- 雲端計算與網格計算的深入比較
- 【計算機組成原理】第6章 計算機的運算方法計算機
- 雲端計算的前身