SELECT COUNT(t.id)
FROM test t
WHERE t.status = 1
AND t.id NOT IN (
SELECT DISTINCT a.app_id
FROM test2 a
WHERE a.type = 1
AND a.rule_id IN (152, 153, 154)
);
執行計劃:FILTER + NOT EXISTS 相關子查詢,**176 萬 consistent gets**,耗時 35 分鐘。
關鍵函數 LNNVL("A"."APP_ID" <> :B1):將「不等於」轉為三值邏輯處理,導致逐行評估極慢。
SELECT COUNT(*) FROM (
SELECT t.id FROM test t WHERE t.status = 1
MINUS
SELECT DISTINCT a.app_id
FROM test2 a
WHERE a.type = 1 AND a.rule_id IN (152, 153, 154)
);
執行計劃:MINUS → 兩邊 SORT UNIQUE → 集合差集,**2,240 consistent gets**,耗時 **< 1 秒**。
| 指標 | NOT IN | MINUS |
|---|---|---|
| Consistent Gets | 1,762,169 | 2,240 |
| 排序操作 | 0 | 2 (memory) |
| 執行時間 | ~35 分鐘 | < 1 秒 |
MINUS(Oracle)/ EXCEPT(標準 SQL、PostgreSQL、SQL Server)需**兩邊欄位數、型別一致**A NOT IN B ≡ A EXCEPT B(去重後)MySQL 中可用 LEFT JOIN ... WHERE b.id IS NULL 或 NOT EXISTS 達到類似效果:
SELECT COUNT(*)
FROM test t
LEFT JOIN (
SELECT DISTINCT app_id FROM test2
WHERE type = 1 AND rule_id IN (152,153,154)
) a ON t.id = a.app_id
WHERE t.status = 1 AND a.app_id IS NULL;
💡 一句話心法:遇到大表 NOT IN 子查詢,**轉換思維為集合差集運算**(MINUS/EXCEPT/LEFT JOIN IS NULL),讓資料庫用排序合併替代逐行判斷。