最左前缀原则是 MySQL 联合索引生效的核心规则:查询条件必须从联合索引的最左侧列开始,且连续使用,才能有效利用索引。
什么是联合索引的最左前缀
假设你创建了联合索引 INDEX idx_name_age_dept (name, age, dept),那么以下查询能用上该索引:
WHERE name = '张三'(只用第1列) WHERE name = '张三' AND age = 25(用第1+2列) WHERE name = '张三' AND age = 25 AND dept = '技术部'(全列都用)但这些写法无法使用该联合索引的全部能力:
WHERE age = 25(跳过 name,索引失效) WHERE dept = '技术部'(只用最右列,不满足最左) WHERE name = '张三' AND dept = '技术部'(中间缺失 age,断层,dept 无法走索引)等值查询 + 范围查询的边界要小心
在联合索引中,一旦出现范围查询(>、等),其右侧所有列都无法用于索引查找(但仍可用于索引覆盖)。
例如索引 (a, b, c):
WHERE a = 1 AND b > 10 AND c = 5 → 只有 a 和 b 走索引查找,c 不参与查找(但若 SELECT 中只有 a/b/c,仍可能走覆盖索引) WHERE a > 1 AND b = 2 → 只有 a 走索引查找,b 完全失效(不能跳过 a 直接筛 b)排序和分组也受最左前缀约束
ORDER BY 或 GROUP BY 要利用联合索引避免 filesort,也必须满足最左前缀:
ORDER BY name, age ✅ 可走索引排序 ORDER BY name ✅ 可走 ORDER BY age ❌ 无法利用索引排序 ORDER BY name, dept ❌ 中间跳过 age,dept 不连续,排序失效注意:如果 WHERE 已经用到 name = ? AND age > ?,那 ORDER BY dept 就完全无法优化——因为 age 是范围,dept 已不在索引查找路径中。
如何设计更合理的联合索引顺序
把区分度高、经常用于等值过滤的列放左边;范围查询列尽量靠右;排序/分组字段若固定,可考虑放在最后(但需确保前面能走索引)。
常见策略:
高频等值条件列优先(如 user_id、status) 多个等值条件时,按查询频率或基数从高到低排(不一定严格,但有助于减少扫描行数) 把 ORDER BY 字段放在索引末尾,仅当前面所有列都能被 WHERE 充分过滤时才有效 避免冗余索引,比如已有 (a,b,c),通常无需再建 (a,b)