首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL JOIN 查詢優化實戰:字符集不一致導致索引失效與覆蓋索引誤導

     編輯:MySQL 資料庫相關知識

問題 SQL

SELECT COUNT(*) 
FROM a JOIN b ON a.S = b.S 
WHERE a.L > '2014-03-30 00:55:00' AND a.L < '2014-03-30 01:00:00';

表結構差異(關鍵)

表欄位 S 定義
aS VARCHAR(64) CHARSET utf8 COLLATE utf8_bin
bS VARCHAR(64) DEFAULT NULL(預設 utf8_general_ci)

錯誤執行計劃

+----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref      | rows    | Extra       |
+----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+
| 1  | SIMPLE      | b     | index | IX_S          | IX_S | 195     | NULL     | 1,038,165| Using index |
| 1  | SIMPLE      | a     | ref   | IX_L,IX_S     | IX_S | 195     | test.b.S | 1       | Using where |
+----+-------------+-------+-------+---------------+------+---------+----------+---------+-------------+
  • 優化器選 b 為驅動表(全索引掃描 103 萬行)
  • 預期應以 a 為驅動(時間範圍僅 63 行)

STRAIGHT_JOIN 驗證假設

EXPLAIN SELECT COUNT(*) FROM a STRAIGHT_JOIN b ON a.S = b.S WHERE ...;
-- a 表 type=range (IX_L, rows=63) ✓
-- b 表 type=index (IX_S, rows=1,038,165) ✗ 仍全掃描!

真相大白:字符集不匹配導致索引失效

EXPLAIN SELECT * FROM a STRAIGHT_JOIN b ON BINARY a.S = b.S WHERE ...;
-- b 表 type=ALL, Extra: Range checked for each record (index map: 0x4)
-- 確認:無 BINARY 時走覆蓋索引掃描(誤以為用上索引),實際無法用索引查找

優化方案對比

核心教訓

  1. JOIN 欄位字符集/校對規則必須完全一致,否則索引失效
  2. 覆蓋索引掃描 ≠ 索引查找:type=index + Using index 可能只是全索引掃描
  3. BINARY col = ... 可臨時解決校對衝突,但最好 DDL 統一
  4. 驗證技巧:SELECT * 破壞覆蓋索引,觀察真實 type 與 key
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案SQL 寫法原理優缺點
1. 子查詢隱式轉換SELECT COUNT(*) FROM b JOIN (SELECT S FROM a WHERE ...) ta ON b.S = ta.S衍生表欄位繼承 utf8_bin,匹配 b.S直觀,隱式轉換
2. 顯式 BINARY(推薦)SELECT COUNT(*) FROM a JOIN b ON BINARY a.S = b.S WHERE ...將 a.S 強制為二進制比較,匹配 b.S 的 utf8_general_ci語義明確,理論更快
3. DDL 修正(根治)ALTER TABLE a MODIFY S VARCHAR(64) CHARSET utf8 COLLATE utf8_general_ci;統一校對規則徹底解決,但需鎖表