联合索引列顺序必须严格遵循最左前缀原则:等值查询字段(=、in)置于最左,尤其是高频过滤字段;范围查询字段(>、between、like 'abc%')紧随其后且仅一个;order by字段须紧接等值列后且方向一致;跳过最左列则索引完全失效。

联合索引的列顺序怎么排才有效
MySQL只按定义顺序从左到右匹配索引字段,跳过最左列就完全失效。比如建了 INDEX (user_id, status, created_at),WHERE status = 'paid' 一句根本用不上——因为没提供 user_id。
实操建议:
- 等值查询字段(
=、IN)放最左,尤其是高频过滤字段,如user_id或tenant_id - 范围查询字段(
>、BETWEEN、LIKE 'abc%')放中间或靠右;它之后的字段无法被索引利用 - 排序字段(
ORDER BY)若想避免Using filesort,必须紧接在等值列后,且方向一致(都ASC或都DESC) - 别把
SELECT里出现的字段硬塞进索引——联合索引不是“所有查询字段打包加进去”
建联合索引该用 ALTER TABLE 还是 CREATE INDEX
两者功能完全等价,语法差异仅在于上下文习惯:ALTER TABLE 更适合已有表的结构变更,CREATE INDEX 更聚焦索引本身,语义更清晰。
推荐统一用 CREATE INDEX,避免和主键/唯一约束混淆:
CREATE INDEX idx_orders_user_status ON orders (user_id, status, created_at);
注意点:
- 索引名必须唯一,重复会报错
ERROR 1061 (42000): Duplicate key name - 字段名要写准确,大小写敏感取决于系统变量
lower_case_table_names,建议全小写+下划线风格 - 别漏掉括号里的逗号分隔,写成
(user_id status created_at)会直接语法错误
为什么 EXPLAIN 显示没走刚建的联合索引
常见现象:明明执行了 CREATE INDEX idx_a_b_c ON t(a,b,c),但 EXPLAIN SELECT * FROM t WHERE b = 1 AND c = 2 仍显示 type: ALL。
原因和对应检查项:
-
WHERE条件缺失最左列(本例缺a)→ 索引完全不生效,补上或换索引 - 字段类型不一致,比如
a是BIGINT,但查询传了字符串'123'→ 触发隐式转换,索引失效 - 索引选择性太低(如
status只有'pending'/'done'两值)→ 优化器判定全表扫描更快,可用FORCE INDEX验证,但别在线上长期用 - 表数据量极小(几百行以内)→ 优化器跳过索引是正常行为,不用干预
多个联合索引能一起建吗
不能。MySQL 不支持单条语句创建多个联合索引,CREATE INDEX idx1, idx2 ON t(a,b), (c,d); 会直接报错 ERROR 1064。
批量本质是脚本化执行,要点:
- 每条
CREATE INDEX必须独立成句,用分号分隔 - 建多个索引时,大表会触发多次全表扫描+排序,IO 压力叠加,比合并成一个更重
- 生成语句前务必查重:
SHOW INDEX FROM orders看是否已存在同名或冗余索引(如已有(a,b),再建(a)就是冗余) - 列名含特殊字符或空格时,必须用反引号包裹:
`user_id`,否则拼接脚本会出错
真正容易被忽略的是索引顺序与查询模式的耦合——不是字段越多越好,而是每列都得在实际 WHERE 或 ORDER BY 中被覆盖,且顺序严格对齐。线上加索引前,一定拿真实慢查 SQL 跑一遍 EXPLAIN,别只看 DDL 执行成功了就以为万事大吉。











