close

oracle execute plan 概念
一、名詞定義
rowid是實際資料列的系統唯一值
recursive call:為了執行某語法所多執行的額外語法,例如trigger
row source:查詢中 返回符合條件的資料子集,可以是某表的全部或部份或join結果
Predicate:where後面那一串條件限制
driving table:查詢中,返回較少row source的 應做為驅動表,hash join中則叫outer table(外層表)
probed table:又稱內層表,或叫被driving table表,即join中另一個返回較多筆數的
concatenated index:連鎖索引,on (c1,c2,c3...) 要注意c1 是主導鍵
                   如果 where c2=xxx 就不會用到連鎖索引了
selectivity:返回資料愈少的適合當索引

二、oracle index scan行為
1.全表掃Full Table Scans,FTS
這種模式當查詢返回資料過多時 會用FTS比較有效率
然而,真對大表格,這種方法會進行非常可觀的I/O量
進而影響系統效能
I/O存取量和db_block_multiblock_read_count 有關

2.rowid lookup
速度最快的模式,但幾乎沒人這樣用..
SQL> select * from t1 where rowid='AAAb/eABFAAAHMDAAB';
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY USER ROWID) OF 'T1'

3.INDEX scan/lookup
先找到index對應中的rowid,再由rowid找出真正資料的值,前者是邏輯,後者會實體io
如下先找索引再找rowid


3-1. index unique scan 索引唯一值掃瞄
alter table t1 add constraints pk_t1 primary key (user_id);
select username from t1 where user_id=22;
---------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |     1 |    11 |     1 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1    |     1 |    11 |     1 |
|   2 |   INDEX UNIQUE SCAN         | PK_T1 |     1 |       |     1 |
這user_id內容雖沒重複但建一般index 仍會以range收場
如果設為限制,則會以唯一值掃瞄

3-2 index range scan:當使用 < > <= >= between  時或排序時
SQL> select username,user_id from t1 where user_id<22;
-----------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost  |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |     1 |    11 |     2 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1      |     1 |    11 |     2 |
|   2 |   INDEX RANGE SCAN          | I_T1_ID |     1 |       |     1 |

select * from t1 where user_id <30 order by user_id;
-----------------------------------------------------
|   0 | SELECT STATEMENT            |         |    26 |   468 |     3 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1      |    26 |   468 |     3 |
|   2 |   INDEX RANGE SCAN          | I_T1_ID |    26 |       |     2 |


3-3 index full scan 索引全掃
 select user_id from t1 order by user_id;
----------------------------------------------------------
|   0 | SELECT STATEMENT |       |   262 |  1048 |     3 |
|   1 |  INDEX FULL SCAN | PK_T1 |   262 |  1048 |     3 |

如果下這種就會被成全掃
 select * from t1 order by user_id;
------------------------------------------
|   0 | SELECT STATEMENT   |      |   262 |  4716 |     3 |
|   1 |  SORT ORDER BY     |      |   262 |  4716 |     3 |
|   2 |   TABLE ACCESS FULL| T1   |   262 |  4716 |     2 |

 

 

3-4 index fast full scan ,和3-3的差別在於沒有排序
 select user_id from t1;
--------------------------------------------------------------
|   0 | SELECT STATEMENT     |       |   262 |  1048 |     2 |
|   1 |  INDEX FAST FULL SCAN| PK_T1 |   262 |  1048 |     2 |


三、表格的合併查詢
表格的join有 對等聯合a.c1=b.c1、非等值聯a.c1<b.c1 =, 外連a.c1=b.c1(+)
而聯合的模式則有
Sort Merge Join SMJ 排序合併聯
Nested Loops NL 巢狀回圈
Hash join  哈希聯

1.SMJ
先處理第一個表格,產生row source-a,再處理第二個表格產生 row source-b
兩個合併
如果row source-a,b在合拼前已排序,速度會變快


#建兩個表格t1,t2都不建索引在8i和10g (默認hash)
select a.username,b.username  from t1 a, t2 b where a.user_id=b.user_id order by a.user_id,b.user_id;
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   MERGE JOIN
   2    1     SORT (JOIN)
   3    2       TABLE ACCESS (FULL) OF 'T2'
   4    1     SORT (JOIN)
   5    4       TABLE ACCESS (FULL) OF 'T1'
10G  不管建不建索引 一律hash join
------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |   262 | 10742 |     6 |
|   1 |  SORT ORDER BY      |      |   262 | 10742 |     6 |
|   2 |   HASH JOIN         |      |   262 | 10742 |     5 |
|   3 |    TABLE ACCESS FULL| T1   |   262 |  2882 |     2 |
|   4 |    TABLE ACCESS FULL| T2   |   262 |  7860 |     2 |
------------------------------------------------------------


2.Nested Loops NL
這種聯合排序最好把外層表用最小row source的當驅動表
理論上會最少io次數,但實際則不定
外層                 內層
row source1.row1 --- probe>row source 2
row source1.row2 --- probe>row source 2
因為外層的每一個對映內層所有行
故外圈(驅動表)要小,內圈(被驅表)要有索引(最好是唯一索) 會有最佳 解

例如t1 ,t2建索引
8i t1,t2不管單建 或各建索引 情況都會比都不建好些
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (ORDER BY)
   2    1     NESTED LOOPS
   3    2       TABLE ACCESS (FULL) OF 'T2'
   4    2       TABLE ACCESS (BY INDEX ROWID) OF 'T1'
   5    4         INDEX (RANGE SCAN) OF 'I_T1_ID' (NON-UNIQUE)

3.Hash join, HJ
oracle 7.3以後新增,理論上比SMJ,NL更有效率,且只用在CBO上
它的作法是用較小row source那個當hash table和bitmap
第二個表用來被hansed與第一個表格產生的 hash table 搭配
hash_join_enabled=true
hash_area_size
只能用在等值聯結 a.c1 = b.c1

先把index拿掉,回到兩個都fts時 再
analyze table t1 estimate statistics;
analyze table t2 estimate statistics;

 select a.created from t1 a, t2 b where  a.user_id=b.user_id;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=161 Bytes=2093)
   1    0   HASH JOIN (Cost=3 Card=161 Bytes=2093)
   2    1     TABLE ACCESS (FULL) OF 'T1' (Cost=1 Card=161 Bytes=1610)
   3    1     TABLE ACCESS (FULL) OF 'T2' (Cost=1 Card=161 Bytes=483)

4.Cartesian product
笛卡兒乘級
這個非常可怕,無限乘上去,一般有設定2-3層 即停止 免得拖死整個db
a.n * b.m
有幾行就乘上去 結果嚇死人

 

 

arrow
arrow
    全站熱搜

    哈哈小熊 發表在 痞客邦 留言(7) 人氣()