看懂Oracle中的執行計劃

迷倪小魏發表於2017-11-30

  

從事Oracle相關的工作,從最初的一臉懵逼到現在的略有所知,也來總結一下自己最近學習關於OracleSQL語句的執行計劃的相關內容。下面是文章的目錄結構:

 

一、什麼是Oracle執行計劃?


執行計劃是一條查詢語句在
Oracle中的執行過程或訪問路徑的描述

 
 

二、怎樣檢視Oracle執行計劃?

2.1 explain plan for命令檢視執行計劃


sql*plus中,執行如下命令:

1)explain plan for select * from XXXX; 

2)select * from table(dbms_xplan.display); 

 


2.2 SET AUTOTRACE ON檢視執行計劃

語法:SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]

序號

命令

解釋

1

SET AUTOTRACE OFF

此為預設值,即關閉Autotrace 

2

SET AUTOTRACE ON EXPLAIN

只顯示執行計劃

3

SET AUTOTRACE ON STATISTICS

只顯示執行的統計資訊

4

SET AUTOTRACE ON

包含2,3兩項內容

5

SET AUTOTRACE TRACEONLY

ON相似,但不顯示語句的執行結果

 

 


2.3 PLSQL Developer檢視執行計劃

 

① 配置執行計劃需要顯示的項:

工具—>首選項 —>視窗型別—>計劃視窗—>根據需要配置要顯示在執行計劃中的列

執行計劃的常用列欄位解釋:

基數(Rows):Oracle估計的當前操作的返回結果集行數

位元組(Bytes):執行該步驟後返回的位元組數

耗費(COST)、CPU耗費:Oracle估計的該步驟的執行成本,用於說明SQL執行的代價,理論上越小越好(該值可能與實際有出入)

時間(Time):Oracle估計的當前操作所需的時間

 

② 開啟執行計劃:

SQL視窗執行完一條select語句後按 F5 即可檢視剛剛執行的這條查詢語句的執行計劃

 

注:在PLSQL中使用SQL命令檢視執行計劃的話,某些SQL*PLUS命令PLSQL無法支援,比如SET AUTOTRACE ON


三、看懂Oracle執行計劃

 

3.1 執行順序:

根據Operation縮排來判斷,縮排最多的最先執行;(縮排相同時,最上面的最先執行)

例:上圖中 INDEX RANGE SCAN INDEX UNIQUE SCAN 兩個動作縮排最多,最上面的 INDEX RANGE SCAN 先執行;

同一級如果某個動作沒有子ID就最先執行

同一級的動作執行時遵循最上最右先執行的原則

例:上圖中 TABLE ACCESS BY GLOBAL INDEX ROWID TABLE ACCESS BY INDEX ROWID 兩個動作縮排都在同一級,則位於上面的 TABLE ACCESS BY GLOBAL INDEX ROWID 這個動作先執行;這個動作又包含一個子動作 INDEX RANGE SCAN,則位於右邊的子動作 INDEX RANGE SCAN 先執行;

 

圖示中的SQL執行順序即為:

INDEX RANGE SCAN —> TABLE ACCESS BY GLOBAL INDEX ROWID —> INDEX UNIQUE SCAN —> TABLE ACCESS BY INDEX ROWID —> NESTED LOOPS OUTER —> SORT GROUP BY —> SELECT STATEMENT, GOAL = ALL_ROWS

(注:PLSQL提供了檢視執行順序的功能按鈕(上圖中的紅框部分)

 


3.2 對圖中動作的一些說明:

1、上圖中 TABLE ACCESS BY …  即描述的是該動作執行時表訪問(或者說Oracle訪問資料)的方式;

表訪問的幾種方式:(非全部)

TABLE ACCESS FULL(全表掃描)

TABLE ACCESS BY ROWID(透過ROWID的表存取)

TABLE ACCESS BY INDEX SCAN(索引掃描)

 

1TABLE ACCESS FULL(全表掃描):

Oracle會讀取表中所有的行,並檢查每一行是否滿足SQL語句中的 Where 限制條件;全表掃描時可以使用多塊讀(即一次I/O讀取多塊資料塊)操作,提升吞吐量;

使用建議:資料量太大的表不建議使用全表掃描,除非本身需要取出的資料較多,佔到表資料總量的 5% ~ 10% 或以上

 

2TABLE ACCESS BY ROWID(透過ROWID的表存取):

先說一下什麼是ROWID

ROWID是由Oracle自動加在表中每行最後的一列偽列,既然是偽列,就說明表中並不會物理儲存ROWID的值;

你可以像使用其它列一樣使用它,只是不能對該列的值進行增、刪、改操作;一旦一行資料插入後,則其對應的ROWID在該行的生命週期內是唯一的,即使發生行遷移,該行的ROWID值也不變。

 

讓我們再回到 TABLE ACCESS BY ROWID 來:

行的ROWID指出了該行所在的資料檔案、資料塊以及行在該塊中的位置,所以透過ROWID可以快速定位到目標資料上,這也是Oracle中存取單行資料最快的方法;

 

3TABLE ACCESS BY INDEX SCAN(索引掃描):

在索引塊中,既儲存每個索引的鍵值,也儲存具有該鍵值的行的ROWID

一個數字列上建索引後該索引可能的概念結構如下圖:

所以索引掃描其實分為兩步:

Ⅰ:掃描索引得到對應的ROWID

Ⅱ:透過ROWID定位到具體的行讀取資料

 

-----------------------------------索引掃描延伸--------------------------------

索引掃描又分五種:

INDEX UNIQUE SCAN(索引唯一掃描)

INDEX RANGE SCAN(索引範圍掃描)

INDEX FULL SCAN(索引全掃描)

INDEX FAST FULL SCAN(索引快速掃描)

INDEX SKIP SCAN(索引跳躍掃描)

 

a)INDEX UNIQUE SCAN(索引唯一掃描):

針對唯一性索引(UNIQUE INDEX)的掃描,每次至多隻返回一條記錄;

表中某欄位存在 UNIQUEPRIMARY KEY 約束時,Oracle常實現唯一性掃描;

 

b)INDEX RANGE SCAN(索引範圍掃描):

使用一個索引存取多行資料;

發生索引範圍掃描的三種情況:

在唯一索引列上使用了範圍運算子(如:><<>>=<=between

在組合索引上,只使用部分列進行查詢(查詢時必須包含前導列,否則會走全表掃描)

對非唯一索引列上進行的任何查詢

 

c)INDEX FULL SCAN(索引全掃描):

進行全索引掃描時,查詢出的資料都必須從索引中可以直接得到(注意全索引掃描只有在CBO模式下才有效)

 

-------------------------- 延伸閱讀:Oracle最佳化器簡述 -------------------------                                                                      

Oracle中的最佳化器是SQL分析和執行的最佳化工具,它負責生成、制定SQL的執行計劃。
Oracle的最佳化器有兩種:
●RBO(Rule-Based Optimization) 基於規則的最佳化器
●CBO(Cost-Based Optimization) 基於代價的最佳化器
RBO
RBO有嚴格的使用規則,只要按照這套規則去寫SQL語句,無論資料表中的內容怎樣,也不會影響到你的執行計劃;
換句話說,RBO對資料“不敏感”,它要求SQL編寫人員必須要了解各項細則;
RBO一直沿用至ORACLE 9i,從ORACLE 10g開始,RBO已經徹底被拋棄。

CBO

CBO是一種比RBO更加合理、可靠的最佳化器,在ORACLE 10g中完全取代RBO;
CBO透過計算各種可能的執行計劃的“代價”,即COST,從中選用COST最低的執行方案作為實際執行方案;
它依賴資料庫物件的統計資訊,統計資訊的準確與否會影響CBO做出最優的選擇,也就是對資料“敏感”。

--------------------------------------------------------------------------------

 

d)INDEX FAST FULL SCAN(索引快速掃描):

掃描索引中的所有的資料塊,與 INDEX FULL SCAN 類似,但是一個顯著的區別是它不對查詢出的資料進行排序(即資料不是以排序順序被返回)

 

e)INDEX SKIP SCAN(索引跳躍掃描):

Oracle 9i後提供,有時候複合索引的前導列(索引包含的第一列)沒有在查詢語句中出現,oralce也會使用該複合索引,這時候就使用的INDEX SKIP SCAN;

 

什麼時候會觸發 INDEX SKIP SCAN 呢?

前提條件:表有一個複合索引,且在查詢時有除了前導列(索引中第一列)外的其他列作為條件,並且最佳化器模式為CBO

Oracle發現前導列的唯一值個數很少時,會將每個唯一值都作為常規掃描的入口,在此基礎上做一次查詢,最後合併這些查詢;

 

例如:

假設表empename(僱員名稱)、job(職位名)、sex(性別)三個欄位,並且建立了如create index idx_emp on emp (sex, ename, job) 的複合索引;

因為性別只有 '' '' 兩個值,所以為了提高索引的利用率,Oracle可將這個複合索引拆成 ('', ename, job)('', ename, job) 這兩個複合索引;

當查詢 select * from emp where job = 'Programmer' 時,該查詢發出後:

Oracle先進入sex''的入口,這時候使用到了 ('', ename, job) 這條複合索引,查詢 job = 'Programmer' 的條目;再進入sex''的入口,這時候使用到了 ('', ename, job) 這條複合索引,查詢 job = 'Programmer' 的條目;

最後合併查詢到的來自兩個入口的結果集。

 

2、上圖中的 NESTED LOOPS … 描述的是表連線方式;

JOIN關鍵字用於將兩張表作連線,一次只能連線兩張表,JOIN操作的各步驟一般是序列的(在讀取做連線的兩張表的資料時可以並行讀取);

表(row source)之間的連線順序對於查詢效率有很大的影響,對首先存取的表(驅動表)先應用某些限制條件(Where過濾條件)以得到一個較小的row source,可以使得連線效率提高。

 

-----------延伸閱讀:驅動表(Driving Table)與匹配表(Probed Table------------

驅動表(Driving Table):
表連線時首先存取的表,又稱外層表(Outer Table),這個概念用於NESTED LOOPS(巢狀迴圈)與 HASH JOIN(雜湊連線)中;
如果驅動表返回較多的行資料,則對所有的後續操作有負面影響,故一般選擇小表(應用Where限制條件後返回較少行數的表)作為驅動表。

匹配表(Probed Table):
又稱為內層表(Inner Table),從驅動表獲取一行具體資料後,會到該表中尋找符合連線條件的行。故該表一般為大表(應用Where限制條件後返回較多行數的表)。

--------------------------------------------------------------------------------

 

表連線的幾種方式:

SORT MERGE JOIN(排序-合併連線)

NESTED LOOPS(巢狀迴圈)

HASH JOIN(雜湊連線)

CARTESIAN PRODUCT(笛卡爾積)

注:這裡將首先存取的表稱作 row source 1,將之後參與連線的表稱作 row source 2

 

1SORT MERGE JOIN(排序-合併連線)

假設有查詢:select a.name, b.name from table_A a join table_B b on (a.id = b.id)

 

內部連線過程:

a) 生成 row source 1 需要的資料,按照連線操作關聯列(如示例中的a.id)對這些資料進行排序

b) 生成 row source 2 需要的資料,按照與 a) 中對應的連線操作關聯列(b.id)對資料進行排序

c) 兩邊已排序的行放在一起執行合併操作(對兩邊的資料集進行掃描並判斷是否連線)

 

延伸:
如果示例中的連線操作關聯列 a.idb.id 之前就已經被排過序了的話,連線速度便可大大提高,因為排序是很費時間和資源的操作,尤其對於有大量資料的表。
故可以考慮在 a.idb.id 上建立索引讓其能預先排好序。不過遺憾的是,由於返回的結果集中包括所有欄位,所以通常的執行計劃中,即使連線列存在索引,也不會進入到執行計劃中,除非進行一些特定列處理(如僅僅只查詢有索引的列等)。
排序-合併連線的表無驅動順序,誰在前面都可以;
排序-合併連線適用的連線條件有: <<==>>= ,不適用的連線條件有: <>like

 

2NESTED LOOPS(巢狀迴圈)

內部連線過程:

a) 取出 row source 1 row 1(第一行資料),遍歷 row source 2 的所有行並檢查是否有匹配的,取出匹配的行放入結果集中

b) 取出 row source 1 row 2(第二行資料),遍歷 row source 2 的所有行並檢查是否有匹配的,取出匹配的行放入結果集中

c) ……

row source 1 (即驅動表)中返回了 N 行資料,則 row source 2 也相應的會被全表遍歷 N 次。

因為 row source 1 的每一行都會去匹配 row source 2 的所有行,所以當 row source 1 返回的行數儘可能少並且能高效訪問 row source 2(如建立適當的索引)時,效率較高。

 

延伸:

巢狀迴圈的表有驅動順序,注意選擇合適的驅動表。
巢狀迴圈連線有一個其他連線方式沒有的好處是:可以先返回已經連線的行,而不必等所有的連線操作處理完才返回資料,這樣可以實現快速響應。
應儘可能使用限制條件(Where過濾條件)使驅動表(row source 1)返回的行數儘可能少,同時在匹配表(row source 2)的連線操作關聯列上建立唯一索引(UNIQUE INDEX)或是選擇性較好的非唯一索引,此時巢狀迴圈連線的執行效率會變得很高。若驅動表返回的行數較多,即使匹配表連線操作關聯列上存在索引,連線效率也不會很高。


 

3HASH JOIN(雜湊連線)

雜湊連線只適用於等值連線(即連線條件為  = 

HASH JOIN對兩個表做連線時並不一定是都進行全表掃描,其並不限制表訪問方式;

 

內部連線過程簡述:

a) 取出 row source 1(驅動表,在HASH JOIN中又稱為Build Table) 的資料集,然後將其構建成記憶體中的一個 Hash TableHash函式的Hash KEY就是連線操作關聯列),建立Hash點陣圖(bitmap

b) 取出 row source 2(匹配表)的資料集,對其中的每一條資料的連線操作關聯列使用相同的Hash函式並找到對應的 a) 裡的資料在 Hash Table 中的位置,在該位置上檢查能否找到匹配的資料

 

----------------------------延伸閱讀:Hash Table相關---------------------------

來自Wiki的解釋:
In computing, a hash table (hash map) is a data structure used to implement an associative array, a structure that can map keys to values. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found.
雜湊(hash)技術:在記錄的儲存位置和記錄具有的關鍵字key之間建立一個對應關係 f ,使得輸入key後,可以得到對應的儲存位置 f(key),這個對應關係 f 就是雜湊(雜湊)函式;

採用雜湊技術將記錄儲存在一塊連續的儲存空間中,這塊連續的儲存空間就是雜湊表(雜湊表)

不同的key經同一雜湊函式雜湊後得到的雜湊值理論上應該不同,但是實際中有可能相同,相同時即是發生了雜湊(雜湊)衝突,解決雜湊衝突的辦法有很多,比如HashMap中就是用鏈地址法來解決雜湊衝突;

雜湊表是一種面向查詢的資料結構,在輸入給定值後查詢給定值對應的記錄在表中的位置以獲取特定記錄這個過程的速度很快。


-------------------------------------------------------------------------------

 

HASH JOIN的三種模式:

OPTIMAL HASH JOIN

ONEPASS HASH JOIN

MULTIPASS HASH JOIN

 

1) OPTIMAL HASH JOIN

OPTIMAL 模式是從驅動表(也稱Build Table)上獲取的結果集比較小,可以把根據結果集構建的整個Hash Table都建立在使用者可以使用的記憶體區域裡。

連線過程簡述:

Ⅰ:首先對Build Table內各行資料的連線操作關聯列使用Hash函式,把Build Table的結果集構建成記憶體中的Hash Table。如圖所示,可以把Hash Table看作記憶體中的一塊大的方形區域,裡面有很多的小格子,Build Table裡的資料就分散分佈在這些小格子中,而這些小格子就是Hash Bucket(見上面Wiki的定義)。

Ⅱ:開始讀取匹配表(Probed Table)的資料,對其中每行資料的連線操作關聯列都使用同上的Hash函式,定位Build Table裡使用Hash函式後具有相同值資料所在的Hash Bucket

Ⅲ:定位到具體的Hash Bucket後,先檢查Bucket裡是否有資料,沒有的話就馬上丟掉匹配表(Probed Table)的這一行。如果裡面有資料,則繼續檢查裡面的資料(驅動表的資料)是否和匹配表的資料相匹配。

 

2) ONEPASS HASH JOIN

從驅動表(也稱Build Table)上獲取的結果集較大,無法將根據結果集構建的Hash Table全部放入記憶體中時,會使用 ONEPASS 模式。

連線過程簡述:

Ⅰ:對Build Table內各行資料的連線操作關聯列使用Hash函式,根據Build Table的結果集構建Hash Table後,由於記憶體無法放下所有的Hash Table內容,將導致有的Hash Bucket放在記憶體裡,有的Hash Bucket放在磁碟上,無論放在記憶體裡還是磁碟裡,Oracle都使用一個Bitmap結構來反映這些Hash Bucket的狀態(包括其位置和是否有資料)。

Ⅱ:讀取匹配表資料並對每行的連線操作關聯列使用同上的Hash函式,定位BitmapBuild Table裡使用Hash函式後具有相同值資料所在的Bucket。如果該Bucket為空,則丟棄匹配表的這條資料。如果不為空,則需要看該Bucket是在記憶體裡還是在磁碟上。

如果在記憶體中,就直接訪問這個Bucket並檢查其中的資料是否匹配,有匹配的話就返回這條查詢結果。

如果在磁碟上,就先把這條待匹配資料放到一邊,將其先暫存在記憶體裡,等以後積累了一定量的這樣的待匹配資料後,再批次的把這些資料寫入到磁碟上(上圖中的 Dump probe partitions to disk)。

Ⅲ:當把匹配表完整的掃描了一遍後,可能已經返回了一部分匹配的資料了。接下來還有Hash Table中一部分在磁碟上的Hash Bucket資料以及匹配表中部分被寫入到磁碟上的待匹配資料未處理,現在Oracle會把磁碟上的這兩部分資料重新匹配一次,然後返回最終的查詢結果。

 

3) MULTIPASS HASH JOIN

當記憶體特別小或者相對而言Hash Table的資料特別大時,會使用 MULTIPASS 模式。MULTIPASS會多次讀取磁碟資料,應儘量避免使用該模式。

 

3、上圖中的 … OUTER 描述的是表連線型別

表連線的兩種型別:

INNER JOIN(內連線)

OUTER JOIN(外連線)

 

透過下面的示例進行演示:

現有test1test2兩表,test1test2表資訊如下:

   

 

下面的例子都用test1test2兩表來演示。

(1) INNER JOIN(內連線)

只返回兩表中相匹配的記錄。

INNER JOIN 又分為兩種:

等值連線(連線條件為 = 

非等值連線(連線條件為 ,如  >  >=  <  <=  等)

 

等值連線用的最多,下面以等值連線舉例:

內連線的兩種寫法:

Ⅰ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a inner join test2 b on (a.id = b.id);

Ⅱ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a join test2 b on (a.id = b.id);

連線時只返回滿足連線條件(test1.id = test2.id)的記錄:

 

2OUTER JOIN(外連線):

OUTER JOIN 分為三種:

LEFT OUTER JOIN(可簡寫為 LEFT JOIN,左外連線)

RIGHT OUTER JOIN RIGHT JOIN,右外連線)

FULL OUTER JOIN FULL JOIN,全外連線)

 

a)LEFT JOIN(左連線):

返回的結果不僅包含符合連線條件的記錄,還包含左邊表中的全部記錄。(若返回的左表中某行記錄在右表中沒有匹配項,則右表中的返回列均為空值)

 

兩種寫法:

Ⅰ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a left outer join test2 b on (a.id = b.id);

Ⅱ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a left join test2 b on (a.id = b.id);

返回結果:

 

b)RIGHT JOIN(右連線):

返回的結果不僅包含符合連線條件的記錄,還包含右邊表中的全部記錄。(若返回的右表中某行記錄在左表中沒有匹配項,則左表中的返回列均為空值)

兩種寫法:

Ⅰ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a right outer join test2 b on (a.id = b.id);

Ⅱ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a right join test2 b on (a.id = b.id);

 

返回結果:

 

c)FULL JOIN(全連線):

返回左右兩表的全部記錄。(左右兩邊不匹配的項都以空值代替)

兩種寫法:

Ⅰ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a full outer join test2 b on (a.id = b.id);

Ⅱ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a full outer join test2 b on (a.id = b.id);

 

返回結果:

 

------------------------------延伸閱讀:(+) 運算子-----------------------------

(+) 運算子是Oracle特有的表示法,用來表示外連線(只能表示 左外、右外 連線),需要配合Where語句使用。
特別注意:(+) 運算子在左表的連線條件上表示右連線,在右表的連線條件上表示左連線。
如:
Ⅰ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a,test2 b where a.id = b.id(+);

查詢結果:

實際與左連線select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a left join test2 b on (a.id = b.id);效果等價

Ⅱ:select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a,test2 b where a.id(+) = b.id;

查詢結果:

實際與右連線select a.id ID1, a.name NAME1, b.id ID2, b.name NAME2 from test1 a right join test2 b on (a.id = b.id);效果等價

-------------------------------------------------------------------------------

 

補充:自連線

透過給一個表賦兩個不同的別名讓其與自身內連或外連線

oraclescottschema中有一個表是emp。在emp中的每一個員工都有自己的mgr(經理),並且每一個經理自身也是公司的員工,自身也有自己的經理。

查詢語句如下:

select work.ename worker,mgr.ename  manager from scott.emp work, scott.emp mgr where work.empno=mgr.mgr order by work.ename;

 

四、使用執行計劃進行SQL調優

1、檢視總COST,獲得資源耗費的總體印象 

一般而言,執行計劃第一行所對應的COST(即成本耗費)值,反應了執行這段SQL的總體估計成本,單看這個總成本沒有實際意義,但可以拿它與相同邏輯不同執行計劃的SQL的總體COST進行比較,通常COST低的執行計劃要好一些。

 

2、按照從左至右,從上至下的方法,瞭解執行計劃的執行步驟 

執行計劃按照層次逐步縮排,從左至右看,縮排最多的那一步,最先執行,如果縮排量相同,則按照從上而下的方法判斷執行順序,可粗略認為上面的步驟優先執行。每一個執行步驟都有對應的COST,可從單步COST的高低,以及單步的估計結果集(對應ROWS/基數),來分析表的訪問方式,連線順序以及連線方式是否合理。 

 

3、分析表的訪問方式 

表的訪問方式主要是兩種:全表掃描(TABLE ACCESS FULL)和索引掃描(INDEX SCAN),如果表上存在選擇性很好的索引,卻走了全表掃描,而且是大表的全表掃描,就說明表的訪問方式可能存在問題;若大表上沒有合適的索引而走了全表掃描,就需要分析能否建立索引,或者是否能選擇更合適的表連線方式和連線順序以提高效率。

 

4、分析表的連線方式和連線順序 

表的連線順序:就是以哪張表作為驅動表來連線其他表的先後訪問順序。 

表的連線方式:簡單來講,就是兩個表獲得滿足條件的資料時的連線過程。主要有三種表連線方式,巢狀迴圈(NESTED LOOPS)、雜湊連線(HASH JOIN)和排序-合併連線(SORT MERGE JOIN)。

 

我們常見得是巢狀迴圈和雜湊連線。 

巢狀迴圈:最適用也是最簡單的連線方式。類似於用兩層迴圈處理兩個遊標,外層遊標稱作驅動表,檢索驅動表的資料,一條一條的代入內層遊標,查詢滿足WHERE條件的所有資料,因此內層遊標表中可用索引的選擇性越好,巢狀迴圈連線的效能就越高。 

雜湊連線:先將驅動表的資料按照條件欄位以雜湊的方式放入記憶體,然後在記憶體中匹配滿足條件的行。雜湊連線需要有合適的記憶體,而且必須在CBO最佳化模式下,連線兩表的WHERE條件有等號的情況下才可以使用。雜湊連線在表的資料量較大,表中沒有合適的索引可用時比巢狀迴圈的效率要高。 

 

總結: 

1、這裡看到的執行計劃,只是SQL執行前可能的執行方式,實際執行時可能因為軟硬體環境的不同,而有所改變,而且cost高的執行計劃,不一定在實際執行起來,速度就一定差,我們平時需要結合執行計劃,和實際測試的執行時間,來確定一個執行計劃的好壞。 

 

2、對於表的連線順序,多數情況下使用的是巢狀迴圈,尤其是在索引可用性好的情況下,使用巢狀迴圈式最好的,但當ORACLE發現需要訪問的資料表較大,索引的成本較高或者沒有合適的索引可用時,會考慮使用雜湊連線,以提高效率。排序合併連線的效能最差,但在存在排序需求,或者存在非等值連線無法使用雜湊連線的情況下,排序合併的效率,也可能比雜湊連線或巢狀迴圈要好。 

 


本文參考自:https://www.cnblogs.com/Dreamer-1/p/6076440.html



作者:SEian.G(苦練七十二變,笑對八十一難)

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31015730/viewspace-2148065/,如需轉載,請註明出處,否則將追究法律責任。

相關文章