not in 和 not exists 比較和用法

Anshenwang發表於2024-11-24

儘量不要使用not in(它會呼叫子查詢),而儘量使用not exists(它會呼叫關聯子查詢)。
查詢語句使用了not in,那麼對內外表都進行全表掃描,沒有用到索引;而not exists的子查詢依然能用到表上的索引。所以無論哪個表大,用not exists都比not in 要快。


NOT IN 查詢返回空結果:
即使在子查詢中過濾掉了 NULL 值,NOT IN 仍然可能返回空結果,特別是當 employees 表中的 department_id 為 NULL 時。
NOT EXISTS 查詢返回結果:
NOT EXISTS 不受 NULL 值的影響,能夠正確返回沒有對應 department_id 的員工。
【解決方法】

由於本人,在沒有使用COALESCE,導致每一次的查詢 not in 和 not exists 返回行不匹配,後來查詢才得知在null 處理上有問題導致的。


為了確保 NOT IN 查詢也能正確返回結果,我們需要考慮 employees 表中的 department_id 為 NULL 的情況。我們可以使用 COALESCE 函式來處理 NULL 值。

COALESCE 函式:
COALESCE 函式用於返回第一個非 NULL 的表示式值。在這裡,我們將 NULL 值替換為 -1,以確保 NULL 值不會影響查詢結果。
子查詢:
子查詢中也使用 COALESCE 函式將 NULL 值替換為 -1,以確保子查詢結果集中不包含 NULL 值。


SQL> -- 使用 NOT IN 並處理 NULL 值
SQL> SELECT e.employee_id, e.first_name, e.last_name
2 FROM employees e
3 WHERE COALESCE(e.department_id, -1) NOT IN (
4 SELECT COALESCE(d.department_id, -1)
5 FROM departments d
6 );

EMPLOYEE_ID FIRST_NAME LAST_NAME
----------- -------------------- -------------------------
178 Kimberely Grant
2 Bob Johnson

COALESCE 函式的使用:
使用 HASH JOIN ANTI SNA 可能會導致額外的記憶體開銷,特別是在資料量較大的情況下。
但是,COALESCE 版本可以處理 NULL 值,確保 NOT IN 條件正確

SQL>
SQL> -- 使用 NOT EXISTS
SQL> SELECT e.employee_id, e.first_name, e.last_name
2 FROM employees e
3 WHERE NOT EXISTS (
4 SELECT 1
5 FROM departments d
6 WHERE d.department_id = e.department_id
7 );

EMPLOYEE_ID FIRST_NAME LAST_NAME
----------- -------------------- -------------------------
2 Bob Johnson
178 Kimberely Grant


SELECT e.employee_id, e.first_name, e.last_name
FROM employees e
WHERE NOT EXISTS (
SELECT *
FROM departments d
WHERE d.department_id = e.department_id
);

相關文章