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

MySQL straight_join 強制連接順序優化:從 72 秒到 1.43 秒的實戰案例

     編輯:MySQL 綜合教學

MySQL straight_join 強制連接順序優化:從 72 秒到 1.43 秒的實戰案例

MySQL 僅支持 Nested Loop Join,優化器有時會選錯驅動表導致連接次數爆炸。STRAIGHT_JOIN 可強制連接順序(類似 Oracle USE_NL + LEADING)。本文實戰案例:通過調整驅動表、添加覆蓋索引、配合 STRAIGHT_JOIN,將查詢從 72 秒優化至 1.43 秒。

原始慢 SQL

SELECT DATE(practicetime) date_time, COUNT(DISTINCT a.userid) people_rows
FROM test_log a, USER b
WHERE a.userid = b.userid
  AND b.isfree = 0
  AND LENGTH(b.username) > 4
GROUP BY DATE(practicetime);

執行 1 分 12 秒。

第一步:覆蓋索引優化被驅動表

ALTER TABLE test_log DROP INDEX ix_test_log_userid,
ADD INDEX ix_test_log_userid (userid, practicetime);

執行計劃變為 type: index、Extra: Using index,但耗時僅略微下降,仍 70 秒級。核心瓶頸在 Using filesort 排序 38 萬行數據。

第二步:STRAIGHT_JOIN 強制 USER 做驅動表

SELECT DATE(practicetime) date_time, COUNT(DISTINCT a.userid) people_rows
FROM USER b STRAIGHT_JOIN test_log a
WHERE a.userid = b.userid
  AND b.isfree = 0
  AND LENGTH(b.username) > 4
GROUP BY DATE(practicetime);

執行計劃:

table: b  type: ALL  rows: 42806  Extra: Using where; Using temporary; Using filesort
table: a  type: ref  key: ix_test_log_userid  rows: 38  Extra: Using index

驅動表行數 4.2 萬,被驅動表單次掃描僅 38 行,**總掃描行數從 38 萬降至 4.2 萬**,耗時 **2.56 秒**。

第三步:驅動表加覆蓋索引消除 Using where

ALTER TABLE USER DROP INDEX ix_user_username,
ADD INDEX ix_user_username (username, isfree);

執行計劃 type: index、Extra: Using index; Using temporary; Using filesort,耗時 **1.43 秒**。

優化效果總結

核心心法

  1. 小表驅動大表:STRAIGHT_JOIN 讓結果集小的表(經過 WHERE 過濾後)做驅動表。
  2. 被驅動表必須有高選擇性索引:連接鍵 + WHERE/GROUP BY 列組成覆蓋索引,實現 Using index。
  3. 驅動表也要覆蓋索引:避免 Using where 回表,進一步減少 IO。
  4. 慎用 STRAIGHT_JOIN:僅在確信優化器誤判且數據分佈穩定時使用,否則可能適得其反。

適用場景

  • 多表 JOIN 且優化器明顯選錯驅動表(EXPLAIN rows 差異巨大)。
  • 被驅動表有合適索引支持 ref/eq_ref 訪問。
  • 數據分佈相對穩定,不頻繁大幅波動。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
階段驅動表關鍵索引耗時
原始test_log (38萬)單列 userid72.62s
覆蓋索引test_log(userid, practicetime)~70s
STRAIGHT_JOINUSER (4.2萬)(userid, practicetime)2.56s
驅動表覆蓋USER(username, isfree) + (userid, practicetime)1.43s