嘿嘿~~~SQL真的是一個很神奇的東西
↑如這個圖,SQL這樣下是可以撈得出資料的,但先記一下omb04這個欄位值是NULL
然後呢,當omb04增加 NOT IN的條件時,竟然就撈不出資料了
再然後呢...,我改成用子查詢的寫法,又變得能撈出資料了
還有一個很有趣的,調整exists子查詢寫法後,又撈不出資料了
.
.
.
問題是出在 NOT IN這個謂詞,只要是謂詞就會進行返還TRUE或FALSE的遊戲,但是NULL會返還TRUE還是FALSE呢?
omb04 NOT IN ('MISC-FREIGHT','MISC-M-DISCOUNT') 實際上就是AND Filter的語句,也就是說他根本就是omb04<>'MISC-FREIGHT' AND omb04 <>'MISC-M-DISCOUNT'
然後要記住一件事:null並不會參與匹配(除非附上IS NULL或IS NOT NULL條件)
所以這注定造成AND的結果會被返還FALSE,撈不出資料
至於第三張圖的SQL為什麼可以撈得出資料呢?因為那些撈不出資料的SQL都被優化器安排到Filter了,Filter的特性已於上段說明。
而AND NOT EXISTS (SELECT 1 FROM ni.omb_file b WHERE b.omb04 IN ('MISC-FREIGHT','MISC-M-DISCOUNT') AND b.omb01 = a.omb01)這個陳述式會讓b.omb04 IN ('MISC-FREIGHT','MISC-M-DISCOUNT')該條件被優化器安排到Access,這意味著什麼呢?這意味著就沒有null參不參與匹不匹配的問題。
至於為何SQL優化器會將NOT IN謂詞安排到Filter呢?因為對於優化器來說使用IN才有決定要走INDEX的存取還是TABLE的存取(前者即為索引掃描、後者為全表掃描)的價值;而當使用NOT IN時,通常沒有選擇餘地,使用全表掃描對效能最好,所以就會直接丟到Filter囉~~
重點:
1.只有Filter才有返還TRUE/FALSE的問題,也只有在Filter下,AND的只要有一條件不符即會返還FALSE的結論才會成立。
2.當使用NOT IN謂詞時,Oracle SQL優化器幾乎不會使用Access而是使用Filter
本篇只是提供了一個可以透過改寫SQL而不動到資料(將NULL塞一個空白)的解決方案,至於詳細原理只能以後有時間再分享囉~~~
(反正就是如我之前有一篇談SQL優化的文章有提到,當查詢計畫出現Filter時應想辦法消除Filter)