關於Oracle full outer join 的bug問題分析及處理
full (outer) join是用來全連線兩個表的語法。即希望將A表和B表關聯,能夠得到A表中有而B表中沒有的記錄,或者B表中有而A表中沒有的記錄。
如何判斷是否有該記錄,則透過on子句來關聯。
下面是一個例子:
SQL> with
2 A as(select 1 a, 2 b from dual),
3 B as(select 2 a, 3 b from dual)
4 select * from A full join B
5 on A.a=B.a
6 /
A B A B
---------- ---------- ---------- ----------
1 2
2 3
2 A as(select 1 a, 2 b from dual),
3 B as(select 2 a, 3 b from dual)
4 select * from A full join B
5 on A.a=B.a
6 /
A B A B
---------- ---------- ---------- ----------
1 2
2 3
瞭解了以上基本原理後,我們應該知道,理論上講,A表和B表的在from子句中的順序是沒有關係的,也就是不影響結果。但是,實際上,卻出現了這樣的問題,下面是對這種情況的描述:
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12791 | 349K| 82 (3)| 00:00:01 |
| 1 | VIEW | | 12791 | 349K| 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN RIGHT OUTER| | 12790 | 1124K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 78075 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 12790 | 562K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 1 | 76 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_RISHARESUM | 1 | 45 | 7 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 12790 | 387K| 33 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12791 | 349K| 82 (3)| 00:00:01 |
| 1 | VIEW | | 12791 | 349K| 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN RIGHT OUTER| | 12790 | 1124K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 78075 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 12790 | 562K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 1 | 76 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_RISHARESUM | 1 | 45 | 7 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 12790 | 387K| 33 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
從以上執行計劃來看,在第四步驟,使用的是hash join rigth outer連線方式。而透過改變兩表的擺放順序,得到如下的執行計劃:
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1876 | 52528 | 82 (3)| 00:00:01 |
| 1 | VIEW | | 1876 | 52528 | 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN OUTER | | 1874 | 164K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL| JXC_RISHARESUM | 1735 | 78075 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12790 | 562K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 2 | 152 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 2 | 90 | 33 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 53785 | 7 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1876 | 52528 | 82 (3)| 00:00:01 |
| 1 | VIEW | | 1876 | 52528 | 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN OUTER | | 1874 | 164K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL| JXC_RISHARESUM | 1735 | 78075 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12790 | 562K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 2 | 152 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 2 | 90 | 33 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 53785 | 7 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
注意,此時,執行計劃中的第四個步驟,變成了:hash join outer方式。這個才是我們所期望的方式。那究竟是什麼導致了這個變化呢?檢視他們的謂詞連線邏輯:
hash join right outer的:
3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
4 - access("T2"."D_TRADEDATE"="T1"."D_TRADEDATE"(+) AND
"T2"."D_REGDATE"="T1"."D_REGDATE"(+) AND "T2"."C_FUNDCODE"="T1"."C_FUNDCODE"(+) AND
"T2"."C_FUNDACCO"="T1"."C_FUNDACCO"(+))
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter(NVL("T1"."C_SHARENO",NULL)='26200703200004969020')
4 - access("T2"."D_TRADEDATE"="T1"."D_TRADEDATE"(+) AND
"T2"."D_REGDATE"="T1"."D_REGDATE"(+) AND "T2"."C_FUNDCODE"="T1"."C_FUNDCODE"(+) AND
"T2"."C_FUNDACCO"="T1"."C_FUNDACCO"(+))
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter(NVL("T1"."C_SHARENO",NULL)='26200703200004969020')
hash join outer的:
3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
"T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter("T2"."C_SHARENO"='26200703200004969020')
4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
"T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter("T2"."C_SHARENO"='26200703200004969020')
還是沒有發現明顯的區別。但是實際卻導致了結果的不同。
還原到原始的表連線順序,然後對兩表進行分析,再檢視執行計劃:
SQL> call dbms_stats.gather_table_stats(user, 'JXC_ALLTRADEDAY');
呼叫完成。
SQL> call dbms_stats.gather_table_stats(user, 'JXC_RISHARESUM');
.....
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1738 | 48664 | 82 (3)| 00:00:01 |
| 1 | VIEW | | 1738 | 48664 | 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN OUTER | | 1735 | 191K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL| JXC_RISHARESUM | 1735 | 98895 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12775 | 698K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 3 | 276 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 3 | 168 | 33 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 62460 | 7 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1738 | 48664 | 82 (3)| 00:00:01 |
| 1 | VIEW | | 1738 | 48664 | 82 (3)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
|* 3 | FILTER | | | | | |
|* 4 | HASH JOIN OUTER | | 1735 | 191K| 41 (3)| 00:00:01 |
| 5 | TABLE ACCESS FULL| JXC_RISHARESUM | 1735 | 98895 | 7 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12775 | 698K| 33 (0)| 00:00:01 |
|* 7 | HASH JOIN ANTI | | 3 | 276 | 41 (3)| 00:00:01 |
|* 8 | TABLE ACCESS FULL | JXC_ALLTRADEDAY | 3 | 168 | 33 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | JXC_RISHARESUM | 1735 | 62460 | 7 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
---------------------------------------------------
3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
"T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter("T2"."C_SHARENO"='26200703200004969020')
4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
"T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
"T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
"T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
8 - filter("T2"."C_SHARENO"='26200703200004969020')
可發現,這時原來連線方式的錯誤執行計劃被修正了,改為hash join outer連線。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12932950/viewspace-752670/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【SQL】13 SQL 別名、SQL 連線(JOIN)、SQL INNER JOIN 關鍵字、SQL LEFT JOIN 關鍵字、SQL RIGHT JOIN 關鍵字、SQL FULL OUTER JSQL
- join、inner join、left join、right join、outer join的區別
- Inner Join, Left Outer Join和Association的區別
- oracle SP2-問題處理Oracle
- Oracle 12c因bug導致ORA-04031問題處理過程Oracle
- Oracle日常問題處理ORA-04031Oracle
- ORACLE問題處理十個指令碼Oracle指令碼
- bug及異常處理1
- JVM問題分析處理手冊JVM
- 小白:關於處理“can't find '__main__' module in ”這個問題的詳細處理方式!AI
- linux處理oracle問題常用命令LinuxOracle
- 關於時間 PHP 處理包遇到的問題時間序列化差值問題PHP
- Oracle資料庫中的逐行處理問題NEOracle資料庫
- 二、Git 問題彙總及處理Git
- `FULL JOIN` 和 `UNION ALL`
- React TSLint中常見的問題及處理方法React
- oracle 高水位分析處理Oracle
- 關於在request請求時,處理請求引數的問題
- Oracle CPU使用率過高問題處理Oracle
- ORACLE懸疑分散式事務問題處理Oracle分散式
- 打Oracle PSU時碰到的一些問題處理Oracle
- [BUG反饋]關於ot模型中的時間型別欄位bug問題模型型別
- 如何處理Oracle資料庫中的壞塊問題(轉)Oracle資料庫
- 關於oracle資料庫訊號量的問題Oracle資料庫
- oracle系統表空間過大問題處理Oracle
- Oracle 記一次ORA-00001問題處理Oracle
- pyinstaller打包cx_Oracle庫問題處理記錄Oracle
- 對於數字或者字串有限的問題的處理字串
- Elasticsearch中關於transform的一個問題分析ElasticsearchORM
- 關於驅動在何處上拉的問題
- Oracle OER 7451 in Load Indicator : Error Code = OSD-04500的問題處理OracleIndicatorError
- Oracle 11g ORA-600 [kjbrcrcvt:lms] 問題處理Oracle
- Oracle日常問題處理-資料庫無法啟動Oracle資料庫
- 關於Cordova框架對URL攔截導致通訊丟失問題的處理框架
- 關於Python中的日期處理Python
- [提問交流]小問題關於外掛開發的欄位定義bug
- Docker使用Calico網路模式配置及問題處理Docker模式
- Centos7 配置靜態ip及問題處理CentOS
- redhat7 搭建oracle 11g RAC 問題與處理RedhatOracle