MySQL 處理 JOIN 時,不會一次把所有表讀進記憶體再比對,而是採用 Nested Loop Join(巢狀迴圈連接):
關鍵結論:被查找的表(非驅動表)必須在關聯欄位上有索引,否則每次查找都是全表掃描,效能呈指數級惡化。
SELECT * FROM `tblA`, `tblB`, `tblC`
WHERE `tblA`.`col1` = `tblB`.`col1`
AND `tblA`.`col2` = `tblC`.`col1`;
+-------+------+---------------+------+---------+------+------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+------+---------------+------+---------+------+------+-------------+
| tblA | ALL | NULL | NULL | NULL | NULL | 1000 | |
| tblB | ALL | NULL | NULL | NULL | NULL | 1000 | Using where |
| tblC | ALL | NULL | NULL | NULL | NULL | 1000 | Using where |
+-------+------+---------------+------+---------+------+------+-------------+
type=ALL:全表掃描rows=1000:預估掃描 1000 行ALTER TABLE `tblB` ADD INDEX `idx_col1` (`col1`);
+-------+------+---------------+----------+---------+-----------+------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+------+---------------+----------+---------+-----------+------+-------------+
| tblA | ALL | NULL | NULL | NULL | NULL | 1000 | |
| tblB | ref | idx_col1 | idx_col1 | 5 | tblA.col1 | 1 | Using where |
| tblC | ALL | NULL | NULL | NULL | NULL | 1000 | Using where |
+-------+------+---------------+----------+---------+-----------+------+-------------+
tblB.type=ref:使用索引查找,ref=tblA.col1 表示用 tblA 的值去查 idx_col1rows=1:預估每次只查 1 行,效能提升 1000 倍ALTER TABLE `tblC` ADD INDEX `idx_col1` (`col1`);
+-------+------+---------------+----------+---------+-----------+------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+------+---------------+----------+---------+-----------+------+-------------+
| tblA | ALL | NULL | NULL | NULL | NULL | 1000 | |
| tblB | ref | idx_col1 | idx_col1 | 5 | tblA.col1 | 1 | Using where |
| tblC | ref | idx_col1 | idx_col1 | 5 | tblA.col2 | 1 | Using where |
+-------+------+---------------+----------+---------+-----------+------+-------------+
ref,ref=tblA.col2SELECT COUNT(tblB.a_id) AS correct, tblA.type, tblA.se_type
FROM tblA, tblB, tblC, tblD
WHERE tblA.ex_id = tblC.ex_id
AND tblC.st_ex_id = tblB.st_ex_id
AND tblB.q_num = tblA.q_num
AND tblB.se_num = tblA.se_num
AND tblB.ans = tblA.ans
AND tblD.ex_id = tblA.ex_id
AND tblD.exp <> tblB.se_num
AND tblB.ans = tblA.ans
AND tblA.ex_id = 1001
AND tblC.r_id = 542
GROUP BY tblA.type, tblA.se_type;
q_num, se_num, ansINDEX idx_se_q (se_num, q_num)(選擇最常用的兩欄)ref,但 tblA 仍 ALLtblA.ex_id = 1001INDEX idx_ex_id (ex_id)ref,rows=1,完成優化INDEX (a, b, c) 支援 a、a,b、a,b,c 查找ref 而非 ALLSTRAIGHT_JOIN 強制順序:SELECT * FROM tblA STRAIGHT_JOIN tblB ON ...USE INDEX/IGNORE INDEX 引導優化器MySQL JOIN 索引優化的本質是:理解 Nested Loop 機制,針對 EXPLAIN 中每一步「被查找的表」在關聯欄位建索引。掌握「兩兩分析法」,再複雜的多表 JOIN 也能拆解為簡單步驟,系統性地消除全表掃描,將百萬行結果集壓縮至百行級。