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

MySQL 子查詢效能優化:避開 DEPENDENT SUBQUERY 陷阱

     編輯:MySQL 綜合教學

MySQL 子查詢效能優化:避開 DEPENDENT SUBQUERY 陷阱

當你使用 EXPLAIN 分析 SQL 執行計劃時,若發現 select_type 欄位出現 DEPENDENT SUBQUERY,這就是 MySQL 子查詢效能低落的典型訊號。這代表子查詢的執行依賴於外層查詢的結果,導致子查詢需重複執行多次,嚴重拖慢查詢速度。

實戰案例分析

假設有以下查詢語句:

SELECT gid, COUNT(id) AS count 
FROM shop_goods g1 
WHERE status = 0 
  AND gid IN (
    SELECT gid 
    FROM shop_goods g2 
    WHERE sid IN (1519066,1466114,1466110,1466102,1466071,1453929)
  )
GROUP BY gid;

執行 EXPLAIN 後發現 select_type 為 DEPENDENT SUBQUERY,意味著:

  • SUBQUERY:子查詢中的第一個 SELECT
  • DEPENDENT SUBQUERY:子查詢中的第一個 SELECT,且取決於外層查詢

換句話說,MySQL 會先根據外層查詢 SELECT gid, COUNT(id) FROM shop_goods WHERE status=0 GROUP BY gid 產生一個龐大的結果集(假設 85 萬筆),然後對結果集中的每一筆記錄,都執行一次子查詢。即使有索引支援,85 萬次子查詢執行也極其緩慢。

優化策略

方案一:拆分為兩個獨立查詢

先執行子查詢取得 gid 清單,再用應用層或臨時表帶入主查詢,避免關聯子查詢的逐行執行模式。

方案二:改用 JOIN 與衍生表(推薦)

SELECT g1.gid, COUNT(1) 
FROM shop_goods g1,
     (SELECT gid FROM shop_goods WHERE sid IN (1519066,1466114,1466110,1466102,1466071,1453929)) g2
WHERE g1.status = 0 
  AND g1.gid = g2.gid
GROUP BY g1.gid;

再次 EXPLAIN 會出現 DERIVED 關鍵字,表示 MySQL 會先遞歸執行子查詢,將結果存入臨時表,再進行 JOIN 操作。這樣子查詢只執行一次,效能大幅提升。

深度解析:MySQL 如何處理關聯子查詢

根據《高效能 MySQL》第 4.4.1 節所述,MySQL 內部會將 IN 子查詢改寫為 EXISTS 相關子查詢:

-- 原始寫法
SELECT * FROM test WHERE tid IN (SELECT fk_tid FROM sub_test WHERE gid=10);

-- MySQL 實際改寫執行邏輯
SELECT * FROM test WHERE EXISTS (
    SELECT * FROM sub_test WHERE gid=10 AND sub_test.fk_tid = test.tid
);

這導致 MySQL 掃描外層表 test 的所有資料,每筆都帶入子查詢關聯。若外層表資料量大,效能極差。因此,盡量避免使用關聯子查詢,優先考慮 JOIN 或衍生表改寫。

總結

  • 發現 DEPENDENT SUBQUERY 即代表效能隱憂
  • 優先改寫為 JOIN + 衍生表(DERIVED)
  • 或拆分為多個獨立查詢由應用層組合
  • 善用 EXPLAIN 驗證優化成果
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved