詳解表連線順序和連線方式是否影響查詢結果
兩張表連線時,不論A連線B表,還是B表連線A表,連線結果的總數都不會改變,但如果多張表連線,甚至又有外聯結時連線結果的總數是否會發生變化,且原因是什麼,帶著這個問題抓取產品庫中的一條典型SQL進一步分析。
有三張表HQ_READ.UP_LOAD_SERLNO_0721 ,MCS_HQ.HI_SALE_CHNL ,MCS_HQ.MA_CHNL 分別叫T1,T2,T3
,T1裡有23980條資料,如果按T1外聯結T2,再內連結T3的順序結果是4356條資料,
但現在按照自己的設想,SQL不變,但改變表連線順序,看看是否會改變查詢結果中資料的總數。查詢結果設想已T1的資料為準,表連線順序是T2,T3表自然連線後再與T1做外連線,總數是T1表的資料條數23980,所以我用hint方式改變表連線順序
執行計劃也顯示T2和T3內連結,再和T1外聯結,因此我認為最後外聯結出來的資料應該是23980條資料,但結果依然是4356條資料,我們看詳細的執行計劃,如下列出了兩種情況,例1是T1,T2外聯結後再與T3做自然連線的順序對應的執行計劃,例2是用hint改變了連線順序T2,T3自然連線後再與T1外聯結對應的執行計劃。
例1 未改變表連線順序,預計4356條資料,實際4356條資料
SQL> SELECT COUNT(*)
2 FROM MCS_HQ_READ.UP_LOAD_SERLNO_0721 T1
3 ,MCS_HQ.HI_SALE_CHNL T2
4 ,MCS_HQ.MA_CHNL T3
5 WHERE T1.SERL_NO = T2.SERL_NO(+)
6 AND T2.UPPR_SHOP_SUPP_CHNL_ID = T3.CHNL_ID
7 ;
執行計劃
----------------------------------------------------------
Plan hash value: 3070468476
--------------------------------------------------------------------------------
-----------------------------------------------------
| Id | Operation | Name | Rows | By
tes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
138 | | 66465 (1)| 00:13:18 | | |
| 1 | SORT AGGREGATE | | 1 |
138 | | | | | |
|* 2 | HASH JOIN | | 32555 | 4
387K| 4456K| 66465 (1)| 00:13:18 | | |
| 3 | NESTED LOOPS | | |
| | | | | |
| 4 | NESTED LOOPS | | 32555 | 4
069K| | 65162 (1)| 00:13:02 | | |
| 5 | TABLE ACCESS FULL | UP_LOAD_SERLNO_0721 | 32555 | 3
242K| | 22 (0)| 00:00:01 | | |
|* 6 | INDEX UNIQUE SCAN | UX_HI_SALE_CHNL_1 | 1 |
| | 1 (0)| 00:00:01 | | |
| 7 | TABLE ACCESS BY GLOBAL INDEX ROWID| HI_SALE_CHNL | 1 |
26 | | 2 (0)| 00:00:01 | ROWID | ROWID |
| 8 | INDEX FAST FULL SCAN | PK_MA_CHNL | 582K| 5
685K| | 473 (1)| 00:00:06 | | |
--------------------------------------------------------------------------------
-----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T2"."UPPR_SHOP_SUPP_CHNL_ID"="T3"."CHNL_ID")
6 - access("T1"."SERL_NO"="T2"."SERL_NO")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
17 recursive calls
0 db block gets
60464 consistent gets
1661 physical reads
764 redo size
235 bytes sent via SQL*Net to client
240 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
1 rows processed
例2 hint改變表連線順序,預計結果行數23890 實際4356
SQL> SELECT /*+ LEADING(T2,T3,T1) USE_HASH(T2,T3) USE_HASH(T1) */
2 COUNT(*)
3 FROM MCS_HQ_READ.UP_LOAD_SERLNO_0721 T1
4 ,MCS_HQ.HI_SALE_CHNL T2
5 ,MCS_HQ.MA_CHNL T3
6 WHERE T1.SERL_NO = T2.SERL_NO(+)
7 AND T2.UPPR_SHOP_SUPP_CHNL_ID = T3.CHNL_ID
8 /
執行計劃
----------------------------------------------------------
Plan hash value: 4158379028
--------------------------------------------------------------------------------
---------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc|
Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
---------------------------------------
| 0 | SELECT STATEMENT | | 1 | 138 | |
94889 (1)| 00:18:59 | | |
| 1 | SORT AGGREGATE | | 1 | 138 | |
| | | |
|* 2 | HASH JOIN | | 32555 | 4387K| 3632K|
94889 (1)| 00:18:59 | | |
| 3 | TABLE ACCESS FULL | UP_LOAD_SERLNO_0721 | 32555 | 3242K| |
22 (0)| 00:00:01 | | |
|* 4 | HASH JOIN | | 6585K| 226M| 238M|
79676 (1)| 00:15:57 | | |
| 5 | PARTITION RANGE ALL | | 6585K| 163M| |
66675 (1)| 00:13:21 | 1 | 50 |
| 6 | TABLE ACCESS FULL | HI_SALE_CHNL | 6585K| 163M| |
66675 (1)| 00:13:21 | 1 | 50 |
| 7 | INDEX FAST FULL SCAN| PK_MA_CHNL | 582K| 5685K| |
473 (1)| 00:00:06 | | |
--------------------------------------------------------------------------------
---------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."SERL_NO"="T2"."SERL_NO")
4 - access("T2"."UPPR_SHOP_SUPP_CHNL_ID"="T3"."CHNL_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
7 recursive calls
0 db block gets
316739 consistent gets
314220 physical reads
0 redo size
216 bytes sent via SQL*Net to client
240 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
實際的結果都是一樣的,說明表連線順序不會影響實際結果,但為什麼不會影響呢?如果把同樣的SQL改成子查詢的方式
SELECT
COUNT(*)
FROM MCS_HQ_READ.UP_LOAD_SERLNO_0721 T1
,(SELECT *
FROM MCS_HQ.HI_SALE_CHNL T2
,MCS_HQ.MA_CHNL T3
WHERE T2.UPPR_SHOP_SUPP_CHNL_ID = T3.CHNL_ID
) T2
WHERE T1.SERL_NO = T2.SERL_NO(+)
查詢結果總數就是我們想要的按T1表的資料總數顯示。
通過對比我們發現在多表連線時,雖然表連線順序改變了,但連線條件沒有改變WHERE T1.SERL_NO = T2.SERL_NO(+)
AND T2.UPPR_SHOP_SUPP_CHNL_ID = T3.CHNL_ID
多表連線的條件如上兩個條件,在最終3個表連線後的結果集中都要滿足的資料才能顯示,如果按T2,T3連線,再和T3外聯結的結果,還需要同時滿足如上兩個條件,但實際是T1.SERL_NO = T2.SERL_NO(+) 而 相應資料的T2.UPPR_SHOP_SUPP_CHNL_ID != T3.CHNL_ID
如T1的SERL_NO是10,T2的SERL_NO 是null,而對應T2中的 UPPR_SHOP_SUPP_CHNL_ID 也是null,那麼T3中的CHNL_ID沒有null,上面兩個條件就不同時滿足,因此表連線順序受連線條件限制不會影響查詢結果。
細心的朋友也會看出在多表連線時的執行計劃中並沒有出現外聯結的計劃項,說明優化器早已判斷出T2.UPPR_SHOP_SUPP_CHNL_ID = T3.CHNL_ID是自然連線,只選擇非空做運算,如果是外連線的話,不匹配的T3的所有列都為空的。外聯結是無意義的,所以計劃並沒有使用類似join outer 之類的詞。優化器自動作出了相應優化
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/750077/viewspace-1768408/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 外連線與連線順序
- 表的連線順序是否很重要
- Oracle 表連線方式詳解(外連結、內連線、自連線)Oracle
- oracle連線查詢詳解Oracle
- Oracle確定連線方式的優先順序Oracle
- 連線查詢
- in子查詢與表連線是否等價?
- MySQL之連線查詢和子查詢MySql
- 檢查連線是否有效
- SQL連線查詢SQL
- oracle 連線查詢Oracle
- 【Oracle】--連線查詢Oracle
- MySQL 連線查詢超全詳解MySql
- java字串連線和運算子優先順序Java字串
- sql 連線查詢例項(left join)三表連線查詢SQL
- 檢查網路是否連線
- 連線池和連線數詳解
- MySQL之連線查詢MySql
- exists和連線方式
- JAVA資料庫處理(連線,資料查詢,結果集返回)Java資料庫
- 3.DQL資料查詢語言(內連線,外連線,自連線)
- DNS查詢順序以及方式DNS
- SQL表連線方式詳解SQL
- MySQL not in巢狀查詢改寫成外連線方式MySql巢狀
- MySQL學習-連線查詢MySql
- Hibernate連線查詢join
- 【janes】多表查詢 外連線
- MySQL8:連線查詢MySql
- mysql查詢語句5:連線查詢MySql
- select查詢之四:連線查詢
- MYSQL學習筆記23: 多表查詢(自連線內連線+左右外連線)MySql筆記
- 為什麼Oracle的外連線寫法不同導致查詢結果不同?Oracle
- 連線和半連線
- 靜態連結動態連結的連結順序問題和makefile示例
- MySQL內連線查詢語句MySql
- 分組查詢連線號段
- Sql Server系列:多表連線查詢SQLServer
- SQL複雜查詢多表連線SQL