16 反連線(anti-join)--優化主題系列
反連線(anti-join)
反連線其實是特殊的半連線。只是把in/exists換成了notin/not exists
執行計劃中,看到有NESTED LOOPS ANTI/HASH JOIN ANTI 就表示有反連線
舉個例子(基於HROracle11gR2)下面有2個SQL:
select department_name
from hr.departments dept
where department_id NOT IN
(select department_id from hr.employees emp);
select department_name
from hr.departments dept
where NOT EXISTS (select null from hr.employees emp
where emp.department_id = dept.department_id);
以上兩個SQL不等價
NOT IN執行計劃是filter對吧??
NOT EXISTS就是正常的JOIN方式了吧
令人驚訝的是,not in不返回結果,notexists返回16行。
這裡也說明not in和notexists不能像in和exists那樣隨意改寫SQL。
為什麼用not in不返回結果呢??因為子查詢
select department_id from hr.employees emp
會返回NULL值。Oracle有個缺陷:
in裡面有NULL值會返回結果,比如下面SQL
select department_name from hr.departments dept wheredepartment_id in(10,50,null);
單not in 裡面有NULL值就不會返回結果,直接返回NULL
select department_name from hr.departments dept wheredepartment_id not in(10,50,null);
我們在做SQL優化的時候,一定要注意not in和notexists是不是能等價轉換。
當然了,一般情況下,
現在來過濾掉NULL值。
A LEFT JOIN B 是不是說A有並且B沒有 B用NULL代替
那我加個where條件 IS NULL
B.XXX IS NULL 是不是說明A和B 沒關聯上??
是不是等效於 NOTIN,NOT EXISTS的效果
總結一下in/exists,notin/not exists 一般情況下,當SQL很簡單,他們的執行計劃是一樣的,也就是說他們的效能時一樣的。但是SQL一複雜了,他們的執行計劃就可能不一樣,這個時候就要我們去解決這些問題。這裡,我不會給你們講什麼情況下應該用notin什麼情況下應該用notexists,因為這些理論是沒用的,要具體情況具體分析。後面的章節我會講解半連線和反連線最底層的原理,把最底層原理搞懂之後,大家以後在遇到in和exists,not in和notexists就會迎刃而解了。