联合索引(也叫复合索引)在 MySQL 中是提升多条件查询性能的关键手段,但它的生效有明确规则,并不是只要建了就一定起作用。核心在于最左前缀原则——查询条件必须从索引的最左边列开始连续匹配,中间不能跳过。
联合索引的结构和最左前缀原则
比如你创建了联合索引
INDEX idx_name_age_dept (name, age, dept),它实际构建的是按 name 排序 → 在 name 相同下按 age 排序 → 在 name 和 age 都相同时按 dept 排序的 B+ 树。因此只有满足“从左到右连续”的查询条件才能走索引:
WHERE name = '张三'✅ 走索引(只用第一列)
WHERE name = '张三' AND age > 25✅ 走索引(用了前两列,age 可用于范围查找)
WHERE name = '张三' AND age = 25 AND dept = '技术部'✅ 全部命中
WHERE age = 25❌ 不走索引(跳过了 name)
WHERE name = '张三' AND dept = '技术部'⚠️ 只能用上 name,dept 因为中间断开(缺少 age)无法利用索引排序,会回表或全扫 dept 部分
范围查询之后的列无法使用索引
一旦某列用了范围(
>、
、<code>BETWEEN、
LIKE前缀不固定如
'%abc'),其右侧所有列都失效:
WHERE name = '张三' AND age > 25 AND dept = '技术部'→ dept 列不生效
WHERE name LIKE '张%'→ 是范围,但属于最左列的“有效范围”,后续列仍可继续判断(因为 B+ 树中 '张%' 是连续区间)
WHERE name LIKE '%张'→ 不符合最左前缀,整个索引失效
排序和分组也遵循最左前缀
如果 SQL 中有
ORDER BY或
GROUP BY,想避免 filesort,字段顺序必须和联合索引最左连续部分一致,且方向(ASC/DESC)要匹配(MySQL 8.0+ 支持混合方向,但老版本要求全部一致):
ORDER BY name, age✅ 可利用
(name, age, dept)
ORDER BY age, dept❌ 无法利用(没包含 name)
ORDER BY name DESC, age ASC❌ MySQL 5.7 默认不支持混合排序,会触发 filesort
如何设计高效的联合索引
建索引前先看高频查询模式,优先把等值查询列放前面,再放范围列,最后放排序/分组列。例如常见查询是:
WHERE status = ? AND create_time > ? ORDER BY update_time DESC,那就建
INDEX idx_status_time_update (status, create_time, update_time)。 区分度高的列不必强求放最前,等值条件的列顺序优先级更高 避免冗余索引:已有
(a,b,c)就不用单独建
(a)或
(a,b)用
EXPLAIN验证:重点看
key(是否命中)、
key_len(用了索引多少字节,可反推用了几列)、
Extra(有没有 Using where / Using index / Using filesort)
