首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL NOT IN vs MINUS 優化:邏輯讀從 176 萬降至 2240 的改寫術

     編輯:MySQL 綜合教學

MySQL NOT IN vs MINUS 優化:邏輯讀從 176 萬降至 2240 的改寫術

優化前:NOT IN 子查詢

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):將「不等於」轉為三值邏輯處理,導致逐行評估極慢。

優化後:MINUS 集合運算

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)需**兩邊欄位數、型別一致**
  • MySQL **不支援 MINUS/EXCEPT**,本案例為 Oracle 環境
  • 邏輯等價:A NOT IN B ≡ A EXCEPT B(去重後)
  • 大資料量時,集合運算配合排序去重,遠優於逐行相關子查詢

MySQL 替代方案

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),讓資料庫用排序合併替代逐行判斷。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved