复合索引字段顺序错误会导致全表扫描,type=all、key_len偏小即为信号;因b+树只支持从左开始的连续等值匹配,跳过最左字段或中间出现范围查询均使后续列失效。

复合索引字段顺序错,不是“慢一点”,而是直接退化成全表扫描——EXPLAIN里 type 变 ALL、key_len 明显偏小,就是最直接的信号。
最左前缀原则不是语法限制,是B+树搜索路径的物理事实
MySQL 的联合索引底层是 B+ 树,按定义顺序逐列构建键值。它不支持“跳着匹配”,只认从左开始的连续等值条件。
-
INDEX (a, b, c):WHERE a = 1 AND b = 2 ✅ 能用上 a 和 b;WHERE a = 1 AND c = 3 ❌ c 完全无效(b 没出现) - WHERE b = 2 AND c = 3 ❌ 整个索引根本无法起步(a 缺失)
- WHERE a = 1 AND b > 10 AND c = 5 ❌ c 不走索引(范围查询在 b 上就截断了后续列)
ORDER BY 和 WHERE 共享同一套顺序约束
排序需求会强制索引顺序与 ORDER BY 字段严格对齐,否则触发 Using filesort。
-
SELECT * FROM t WHERE a = 1 ORDER BY a, b✅ 可走(a, b)索引,避免文件排序 -
SELECT * FROM t WHERE a = 1 ORDER BY b, a❌ 即使有(a, b)索引,也无法利用其有序性 - 如果还要
GROUP BY status,但总带WHERE user_id = ?,那(user_id, status)才能让分组在索引内完成,不依赖临时表
低区分度字段放前面,等于主动放弃索引过滤能力
区分度低(比如只有 3–5 个值的 status)本身不是问题,但它当第一列时,会让索引失去“快速定位”价值。
- 即使
status几乎每条查询都带,也别放第一列——除非你确定后续列全是等值且高选择性 - 更合理的做法是:高频等值字段(哪怕区分度一般)放第一列 → 中等区分度 + 组合过滤强的字段放第二列 → 范围条件字段(
>=、BETWEEN)必须放最后 - 用
EXPLAIN看key_len:值越接近索引总字节数,说明用得越充分;如果只用了前几个字节,大概率是顺序或条件写法出了问题
ALTER INDEX 不能“改顺序”,本质是删+建,线上务必谨慎
MySQL 5.7+ 支持 ALGORITHM=INPLACE,但仅限添加/删除索引,不支持修改已有索引字段顺序。
- 想调换
(a, b, c)为(b, a, c)?只能DROP INDEX再CREATE INDEX - 大表上执行会锁表(尤其
LOCK=DEFAULT时),期间新索引不可用,业务可能直接受影响 - 别信“先建新索引再删旧索引”就安全——两个索引同时存在会加重写入负担,且空间翻倍
真正容易被忽略的点:隐式类型转换和函数操作会直接绕过最左前缀判断——哪怕顺序完全正确,WHERE user_id = 123(user_id 是 VARCHAR)或 WHERE YEAR(created_at) = 2023 都会让整个索引失效。顺序只是基础,类型和表达式才是临门一脚。











