概念:子查詢展開(Subquery Unnesting)是優(yōu)化器處理帶子查詢的目標(biāo)sql的一種優(yōu)化手段,它是指優(yōu)化器不再將目標(biāo)sql中子查詢當(dāng)作一個獨立的處理單元來單獨執(zhí)行,而是將該子查詢轉(zhuǎn)換為它自身和外部查詢之間等價的表連接。這種等價連接轉(zhuǎn)換要么是將子查詢展開(即將該子查詢中的表,視圖從子查詢中拿出來,然后和外部查詢中的表,視圖做表連接),要么是不拆開但是會把該子查詢轉(zhuǎn)換為一個內(nèi)嵌視圖(Inline View)然后再和外部查詢中的表,視圖做表連接。Oracle 會確保子查詢展開所對應(yīng)的等價連接轉(zhuǎn)換的正確性,即轉(zhuǎn)換后的sql和原sql在語義上一定是等價的。當(dāng)然不是所有的子查詢都能做子查詢展開,有些子查詢是不能做這種等價表連接轉(zhuǎn)換的,這種情況下oracle就不會對其做子查詢展開,也就是說此時oracle還是會將該子查詢當(dāng)作一個獨立的處理單元來單獨執(zhí)行。另外,在oracle10g以后版本中,對于那種不拆開子查詢但是會把該子查詢轉(zhuǎn)換成一個內(nèi)嵌視圖的子查詢展開,只有當(dāng)經(jīng)過子查詢展開后的等價改寫sql的成本值小于原sql的成本值時,oracle才會對原sql執(zhí)行子查詢展開
創(chuàng)新互聯(lián)主要從事做網(wǎng)站、成都網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)南州晴隆,十余年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
子查詢展開通常都會提高原sql的執(zhí)行效率,因為如果原sql不做子查詢展開,那么通常情況下該子查詢就會在其執(zhí)行計劃的最后一步才被執(zhí)行,并且會走filter類型的執(zhí)行計劃,這也就意味著對于外部查詢所在結(jié)果集的沒一條記錄,該子查詢就會被執(zhí)行多少次,這種執(zhí)行方式的執(zhí)行效率通常情況不會太高,尤其在子查詢中包含兩個或兩個以上表連接時,此時做子查詢展開后的執(zhí)行效率往往會比走filter類型的執(zhí)行計劃高很多。
Oracle 數(shù)據(jù)庫里子查詢前where條件如果是如下這些條件之一,那么這種類型的目標(biāo)sql在滿足了一定條件后就可以做子查詢展開,
single-row,exists,not exists,in ,not in,any,all。
范例1:
SQL> set lines 200 pagesize 1000 in寫法: SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id IN 4 (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700) 5 ; Execution Plan ---------------------------------------------------------- Plan hash value: 2448612695 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 7059 | 158K| | 1583 (1)| 00:00:20 | | | |* 1 | HASH JOIN SEMI | | 7059 | 158K| 1360K| 1583 (1)| 00:00:20 | | | | 2 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 704K| | 405 (1)| 00:00:05 | | | | 3 | PARTITION RANGE ALL| | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | |* 4 | TABLE ACCESS FULL | SALES | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | ---------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- any等價寫法: SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id = ANY 4 (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700) 5 ; Execution Plan ---------------------------------------------------------- Plan hash value: 2448612695 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 7059 | 158K| | 1583 (1)| 00:00:20 | | | |* 1 | HASH JOIN SEMI | | 7059 | 158K| 1360K| 1583 (1)| 00:00:20 | | | | 2 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 704K| | 405 (1)| 00:00:05 | | | | 3 | PARTITION RANGE ALL| | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | |* 4 | TABLE ACCESS FULL | SALES | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | ---------------------------------------------------------------------------------------------------------- exists等價寫法: SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id = ANY 4 (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700) 5 ; Execution Plan ---------------------------------------------------------- Plan hash value: 2448612695 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 7059 | 158K| | 1583 (1)| 00:00:20 | | | |* 1 | HASH JOIN SEMI | | 7059 | 158K| 1360K| 1583 (1)| 00:00:20 | | | | 2 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 704K| | 405 (1)| 00:00:05 | | | | 3 | PARTITION RANGE ALL| | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | |* 4 | TABLE ACCESS FULL | SALES | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | ----------------------------------------------------------------------------------------------------------
不展開,顯然不合理,sales表要執(zhí)行很多次: SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id IN (SELECT /*+ no_unnest */ t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700)
子查詢展開后,變成hash 半連接:
等價寫法:(如果cust_id是唯一鍵值)可以轉(zhuǎn)換為內(nèi)連接:
SELECT t1.cust_last_name, t1.cust_id FROM customers t1, sales t2 WHERE t1.cust_id= t2.cust_id AND t2.amount_sold > 700
如果是not in,則會轉(zhuǎn)換為hash 反連接:
SQL> set autot trace SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id not in 4 (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700); Execution Plan ---------------------------------------------------------- Plan hash value: 2850422635 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 48441 | 1088K| | 1583 (1)| 00:00:20 | | | |* 1 | HASH JOIN ANTI | | 48441 | 1088K| 1360K| 1583 (1)| 00:00:20 | | | | 2 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 704K| | 405 (1)| 00:00:05 | | | | 3 | PARTITION RANGE ALL| | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | |* 4 | TABLE ACCESS FULL | SALES | 560K| 5469K| | 526 (2)| 00:00:07 | 1 | 28 | ----------------------------------------------------------------------------------------------------------
把子查詢轉(zhuǎn)換成內(nèi)聯(lián)視圖:
SELECT t1.cust_last_name, t1.cust_id FROM customers t1 WHERE t1.cust_id NOT IN (SELECT t2.cust_id FROM sales t2, products t3 WHERE t2.prod_id = t3.prod_id and t2.amount_sold > 700) Execution Plan ---------------------------------------------------------- Plan hash value: 1272298339 -------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop | -------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 48441 |1229K| |1665 (1)| 00:00:20 | | | |* 1 | HASH JOIN ANTI | | 48441 |1229K|1360K|1665 (1)| 00:00:20 | | | | 2 | TABLE ACCESS FULL | CUSTOMERS | 55500 | 704K| | 405 (1)| 00:00:05 | | | | 3 | VIEW | VW_NSO_1 | 560K|7110K| | 529 (2)| 00:00:07 | | | |* 4 | HASH JOIN | | 560K|9844K| | 529 (2)| 00:00:07 | | | | 5 | INDEX FULL SCAN | PRODUCTS_PK | 72 | 288 | | 1 (0)| 00:00:01 | | | | 6 | PARTITION RANGE ALL| | 560K|7657K| | 526 (2)| 00:00:07 | 1 | 28 | |* 7 | TABLE ACCESS FULL | SALES | 560K|7657K| | 526 (2)| 00:00:07 | 1 | 28 | --------------------------------------------------------------------------------------------------------------
這里oracle把子查詢轉(zhuǎn)換成內(nèi)聯(lián)視圖 VM_NSO_1,然后再和外部查詢中的表customers做hash半連接。
等價:
SELECT t1.cust_last_name, t1.cust_id FROM customers t1, (SELECT t2.cust_id FROM sales t2, products t3 WHERE t2.prod_id = t3.prod_id AND t2.amount_sold > 700) vm_nso_1 WHERE t1.cust_id semi = vm_nso_1.cust_id
子查詢是否能夠做子查詢展開取決于如下兩個條件:
子查詢展開所對應(yīng)的等價改寫sql和原sql在語義上一定要完全等價的,如果改寫后的sql和原sql并不一定能保持語義上的完全等價,這種類型的子查詢就不能做子查詢展開。
對于不能拆開的子查詢但是會把它轉(zhuǎn)換為一個內(nèi)嵌視圖的子查詢展開,只有經(jīng)過子查詢展開的等價改寫sql成本值小于原sql的成本值。oracle才會對目標(biāo)sql執(zhí)行子查詢展開。
對于子查詢展開的第一種情形(即將子查詢展開,把該子查詢中的表,視圖從子查詢中拿出來,然后和外部查詢中表,視圖做表連接),即使在oracle 10g以后的版本中,oracle也不會考慮子查詢展開的成本,即oracle此時會認(rèn)為這種情形下子查詢展開的效率始終比不展開的效率高,這就意味著如果目標(biāo)sql滿足子查詢展開的第一種情形。則oracle始終會做子查詢展開,而不管經(jīng)過子查詢展開后的等價sql的成本值是否小于原sql的成本值。
當(dāng)前標(biāo)題:Oracle查詢轉(zhuǎn)換之子查詢展開
標(biāo)題來源:http://jinyejixie.com/article32/ggiosc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、服務(wù)器托管、全網(wǎng)營銷推廣、搜索引擎優(yōu)化、App設(shè)計、手機網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)