复合索引字段顺序不能随便调换,因mysql b+树按定义顺序逐列比较,必须从左到右连续匹配最左前缀才能生效;等值查询字段应前置,范围查询靠后且尽量唯一,排序字段需与索引顺序一致以避免filesort。

复合索引的字段顺序为什么不能随便调换
MySQL 的 B+ 树索引是按定义顺序逐列比较的,WHERE 条件只有从左到右连续匹配索引字段时才能生效。比如建了 (a, b, c) 复合索引,WHERE a = 1 AND b = 2 能用上,但 WHERE b = 2 AND c = 3 完全无法利用该索引。
常见错误是把高频过滤字段放在后面,例如用户表按 (status, created_at) 建索引,但实际查询多为 WHERE created_at > '2024-01-01',此时索引几乎无效。
- 最左前缀原则不是“包含即可”,而是“从第一个字段开始连续命中”
- 等值查询字段(
=或IN)应放前面,范围查询(>,BETWEEN,LIKE 'abc%')尽量靠后且只保留一个 - 排序字段如果参与
ORDER BY,需和索引顺序一致才可能避免filesort
哪些查询能真正用上 (user_id, status, created_at) 索引
假设你建了这个三列复合索引,以下查询能命中不同长度的前缀:
SELECT * FROM orders WHERE user_id = 123; -- 用上 (user_id) SELECT * FROM orders WHERE user_id = 123 AND status = 'paid'; -- 用上 (user_id, status) SELECT * FROM orders WHERE user_id = 123 AND status = 'paid' AND created_at > '2024-01-01'; -- 用上全部三列,但 created_at 只用于过滤,不支持后续范围排序 SELECT * FROM orders WHERE user_id = 123 ORDER BY status, created_at; -- 可跳过 filesort
但这些不行:
-
WHERE status = 'paid'—— 缺少user_id,索引失效 -
WHERE user_id = 123 AND created_at > '2024-01-01'—— 跳过status,created_at不会走索引 -
WHERE user_id = 123 ORDER BY created_at—— 中间缺status,无法保证created_at有序
EXPLAIN 中看到 key_len 是多少才说明用对了
key_len 表示 MySQL 实际使用索引字节数。它能帮你确认是否用到了预期字段及长度。比如 user_id 是 BIGINT(8 字节),status 是 ENUM('paid','pending')(1 字节),created_at 是 DATETIME(5 字节),那么:
用 php + mysql 驱动的在线商城系统,我们的目标为中国的中小企业及个人提供最简洁,最安全,最高效的在线商城解决方案,使用了自建的会员积分折扣功能,不同的会员组有不同的折扣,让您的商店吸引更多的后续客户。 系统自动加分处理功能,自动处理会员等级,免去人工处理的工作量,让您的商店运作起来更方便省事 采用了自建的直接模板技术,免去了模板解析时间,提高了代码利用效率 独立开发的购物车系统,使用最
-
key_len = 8→ 只用了user_id -
key_len = 9→ 用了user_id + status -
key_len = 14→ 三个字段都参与了索引查找(注意:范围查询字段之后的字段仍计入key_len,但不再用于查找)
如果 EXPLAIN 显示 key_len 比预期小,或 type 是 index / ALL,大概率是条件没对齐最左前缀。
什么时候该删掉冗余的复合索引
已有 (a, b, c),再建 (a, b) 就是冗余的——前者完全可以覆盖后者。但 (a, c) 不冗余,因为跳过了 b,无法被 (a, b, c) 替代。
检查冗余索引可用 pt-duplicate-key-checker,或手动比对:
- 新索引字段是旧索引的**严格前缀**(如旧:
(a,b,c),新:(a,b))→ 可删新 - 新索引字段数更少,但顺序不同(如旧:
(a,b,c),新:(a,c))→ 不能删,c在旧索引里无法单独跳过b使用 - 有
WHERE + ORDER BY组合需求时,即使字段重复,也可能需要额外索引(如(a, b)用于查询,(a, c)用于排序)
复合索引不是越多越好,每个额外索引都会拖慢写入、增加磁盘占用,并让优化器选择成本上升。线上表加索引前,先看慢查日志里真实出现的 WHERE 和 ORDER BY 组合。









