在 SQL 查詢優化中,EXISTS 與 NOT EXISTS 是處理關聯子查詢的核心運算子。正確理解其邏輯差異與執行機制,對於撰寫高效能查詢至關重要。
| 運算子 | 回傳條件 | 邏輯含義 |
|---|---|---|
| EXISTS | 子查詢回傳至少一行資料 | 「存在」即為真 |
| NOT EXISTS | 子查詢未回傳任何資料 | 「不存在」即為真 |
EXISTS 採用「半連接」策略:一旦子查詢找到符合條件的第一行,立即停止掃描並回傳 TRUE,不再繼續搜尋。這使其在大數據集中極具優勢。
NOT EXISTS 則需掃描完所有符合條件的資料才能確認「不存在」,無法提前終止,相對較慢。
-- 找出有下過訂單的客戶(高效)
SELECT c.* FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
-- 找出從未下單的客戶
SELECT c.* FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
注意:子查詢慣用 SELECT 1 而非 SELECT *,避免不必要的欄位解析開銷。
orders.customer_id)有索引,否則將退化為全表掃描。NOT IN 在子查詢含 NULL 時會回傳空結果,NOT EXISTS 則無此問題,語義更安全。EXISTS 通常優於 INNER JOIN + DISTINCT,因為不需產生中間結果集去重。-- 找出 2023 年有購買「筆電類」商品的 VIP 客戶
SELECT c.* FROM customers c
WHERE c.level = 'VIP'
AND EXISTS (
SELECT 1 FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.customer_id = c.id
AND o.created_at >= '2023-01-01'
AND p.category = '筆電'
);
EXISTS 執行計劃示意:

NOT EXISTS 執行計劃示意:

EXISTS/NOT EXISTS 替代 IN/NOT IN 處理關聯子查詢。NOT EXISTS 可考慮改寫為 LEFT JOIN ... WHERE IS NULL 並配合索引,經實測有時效能更佳。