JOIN 是多表查詢核心,但字符集/校對規則不一致會導致索引失效、隱式轉換、性能下降百倍。本文系統講解 JOIN 分類、基本語法、CROSS JOIN 特性,並通過實測量化「utf8mb4 vs gb2312」字符集不匹配對 LEFT JOIN 性能的毀滅性影響。
-- 基本語法 SELECT ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON condition [WHERE ...] [LIMIT ...] -- 別名簡寫 SELECT a.id, a.title, u.username FROM article a INNER JOIN user u ON a.uid = u.uid
| 類型 | 語義 | 結果行數 |
|---|---|---|
| INNER JOIN | 雙向匹配 (交集) | ≤ min(左表行數, 右表行數) |
| LEFT JOIN | 左表全量 + 右表匹配 (左外連接) | = 左表行數 |
| RIGHT JOIN | 右表全量 + 左表匹配 (右外連接) | = 右表行數 |
-- 替代方案: UNION 模擬 SELECT * FROM a LEFT JOIN b ON a.id = b.id UNION SELECT * FROM a RIGHT JOIN b ON a.id = b.id;
SELECT * FROM a CROSS JOIN b; -- 無 ON 條件 -- MySQL 中 CROSS JOIN = INNER JOIN (無 ON 時) -- 有 ON 時: CROSS JOIN = INNER JOIN
-- 表 t1: utf8mb4 CREATE TABLE t1 (name VARCHAR(50) NOT NULL DEFAULT '', KEY idx_name (name)) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- 表 t2: utf8mb4 (同字符集) CREATE TABLE t2 LIKE t1; INSERT INTO t2 SELECT * FROM t1 LIMIT 1000; -- 表 t3: gb2312 (異字符集) CREATE TABLE t3 LIKE t1; ALTER TABLE t3 MODIFY name VARCHAR(50) CHARSET gb2312; INSERT INTO t3 SELECT * FROM t1 LIMIT 1000;
-- 同字符集 JOIN SELECT SQL_NO_CACHE t1.name, t2.name FROM t1 LEFT JOIN t2 ON t1.name = t2.name WHERE t2.name IS NULL LIMIT 30; -- 異字符集 JOIN SELECT SQL_NO_CACHE t1.name, t3.name FROM t1 LEFT JOIN t3 ON t1.name = t3.name WHERE t3.name IS NULL LIMIT 30;
| 場景 | 耗時 | 說明 |
|---|---|---|
| t1 ↔ t2 (同 utf8mb4) | 0.0010 秒 | 索引生效,ref 類型 |
| t1 ↔ t3 (utf8mb4 vs gb2312) | 0.1871 秒 | **索引失效**,ALL 類型全表掃描 |

-- 同字符集 type: ref, key: idx_name, rows: 1 -- 異字符集 type: ALL, key: NULL, rows: 10000 (全表掃描)
WHERE CONVERT(t1.name USING gb2312) = t3.nameALTER TABLE t3 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 查詢時顯式轉換 SELECT * FROM t1 LEFT JOIN t3 ON t1.name = CONVERT(t3.name USING utf8mb4); -- 8.0 函數索引 ALTER TABLE t3 ADD INDEX idx_name_utf8 ((CONVERT(name USING utf8mb4)));
SET NAMES utf8mb4 / 連接池配置CHARSET=utf8mb4 COLLATE=utf8mb4_general_cipt-online-schema-change 線上轉換ON 條件列、WHERE 過濾列、SELECT 列建立聯合索引EXPLAIN 關注 materialized、derivedWHERE 條件盡早過濾,減少 JOIN 參與行數utf8` vs `utf8mb4` 校對規則不同導致索引失效utf8mb4_general_ci 或 utf8mb4_0900_ai_ci (8.0 默認)COLLATE utf8mb4_bin` 區分大小寫導致業務邏輯錯誤_general_ci`/`_0900_ai_ci`JOIN` 後 `WHERE` 條件導致外連接退化為內連接ON` 子句,左表條件放在 `WHERE`LIMIT`,大數據集用游標/ID 分頁