經驗法則:「LEFT JOIN 左表為主表」**並不總是成立**。MySQL 優化器會根據 WHERE 條件、索引情況、統計信息動態選擇驅動表(主表)。
CREATE TABLE categories ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name VARCHAR(15) NOT NULL, created DATETIME NOT NULL ); CREATE TABLE posts ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, category_id INT UNSIGNED NOT NULL, title VARCHAR(100) NOT NULL, content VARCHAR(200) NOT NULL, created DATETIME NOT NULL, KEY idx_category_id (category_id) );
EXPLAIN SELECT * FROM posts LEFT JOIN categories ON posts.category_id = categories.id WHERE categories.id = 1 ORDER BY posts.created DESC;
ALTER TABLE posts ADD INDEX idx_cat_created (category_id, created);
重新 EXPLAIN,Using filesort 消失。原因:主表 categories 通過 category_id 關聯 posts 時,聯合索引已按 created 排序,直接順序讀取。
ORDER BY categories.created DESC -- 避免 filesort
STRAIGHT_JOIN 強制連接順序(慎用,阻礙優化器)USE INDEX(idx_name) / IGNORE INDEX(idx_name) 引導索引選擇user 表: user_action 表:
id | name user_id | action
1 | libk 1 | jump
2 | zyfon 1 | kick
3 | daodao 1 | jump
2 | run
4 | swim
SQL:
SELECT id, name, action FROM user u LEFT JOIN user_action a ON u.id = a.user_id;
結果:
SELECT u.id, u.name FROM user u LEFT JOIN user_action a ON u.id = a.user_id WHERE a.user_id IS NULL; -- 必須用 IS NULL,且 a.user_id 定義為 NOT NULL
結果:3 | daodao
| 語法 | 等價形式 |
|---|---|
ON a.c1 = b.c1 | USING (c1) |
INNER JOIN | , (逗號連接) |
USE INDEX (key1,key2) | 建議使用索引 |
IGNORE INDEX (key3) | 忽略指定索引 |
EXPLAIN 觀察驅動表順序與 Extra 信息,是調優入門必修課