SELECT * FROM A a LEFT JOIN B b ON a.JOB_ID = b.ID
EXPLAIN SELECT * FROM A a LEFT JOIN B b ON a.JOB_ID = b.ID;
-- type=ALL, rows=22711*1230 ≈ 2.8 億掃描行(近乎笛卡爾積)
原理: MySQL 使用 Block Nested-Loop Join (BNL),驅動表(前表)結果集逐行到被驅動表掃描,**驅動表行數決定總掃描量**。
發現 A 表中 JOB_ID 為 NULL 的行無業務意義,改為 INNER JOIN,過濾無效行。
EXPLAIN 仍為 type=ALL,但掃描行數下降。
B 表 ID 原無主鍵,ALTER TABLE B ADD PRIMARY KEY (ID);
EXPLAIN 顯示 type=ALL 未變,**因為主鍵建立後需重新分析統計信息或建立索引才能生效**。
ALTER TABLE B ADD INDEX idx_id (ID); -- 或直接用主鍵
-- EXPLAIN: type=ref, rows=22711*1 = 2.2 萬掃描行,耗時 0.109s
質變時刻: 索引生效後,BNL 退化為 Index Nested-Loop Join,被驅動表從全表掃描變為索引查找,**總掃描行數 = 驅動表行數 × 1**。
| 步驟 | 動作 | 耗時 | EXPLAIN 關鍵變化 |
|---|---|---|---|
| 0 | 原始 LEFT JOIN | 3.712s | type=ALL, rows=2.8億 |
| 1 | 改 INNER JOIN | 2.745s | type=ALL, rows↓ |
| 2 | B 表加主鍵 | 2.672s | type=ALL(統計未更新) |
| 3 | B 表加索引 | 0.109s | type=ref, rows=2.2萬 |
ANALYZE TABLE 及時更新統計信息,讓優化器看到索引。一句話總結: JOIN 調優核心 = 「被驅動表連接列建索引」+「業務語義選對連接類型」+「統計信息保持新鮮」。