联合索引(也叫复合索引)是 MySQL 中对两个或更多列共同建立的一个 B+ 树索引,它的核心作用是提升多条件查询的效率。它不是多个单列索引的简单叠加,而是一个整体结构——数据按索引列**从左到右依次排序**,就像电话簿先按姓氏、再按名字、最后按中间名排列一样。
联合索引的物理结构是怎样的
以 INDEX idx(a, b, c) 为例:
B+ 树的第一层按 a 列值整体排序 a 相同的记录中,第二层再按 b 排序 a 和 b 都相同的记录中,第三层再按 c 排序 叶子节点不仅存 a、b、c 的值,还包含对应行的主键(用于回表)这种嵌套排序决定了:只有知道前面的列值,后面的列才能被高效定位。这也是“最左前缀原则”的底层原因。
最左前缀原则怎么起作用
查询能否用上联合索引,取决于 WHERE 条件是否构成索引列的**连续左前缀**:
✅ 可用:a = ?、
a = ? AND b = ?、
a = ? AND b = ? AND c = ?✅ 范围查询也支持:
a > ?、
a = ? AND b > ?、
a = ? AND b = ? AND c BETWEEN ? AND ?❌ 无法使用:
b = ?、
c = ?、
a = ? AND c = ?(跳过 b)、
b = ? AND c = ?
注意:MySQL 8.0.13+ 引入了索引跳跃扫描(Index Skip Scan),在第一列区分度很低(比如只有几个固定值)时,可能绕过最左限制使用索引,但这是优化器的主动选择,并非常规路径。
为什么列顺序特别关键
联合索引的列顺序直接影响哪些查询能走索引、以及索引的过滤效率:
高选择性列优先:比如用户表中user_id比
status(如 0/1)区分度高得多,应放前面 等值查询列优先于范围查询列:例如
WHERE dept = 'tech' AND create_time > '2024-01-01',dept 应排在 create_time 前面 排序和分组字段可纳入考虑:如果常查
ORDER BY a, b,联合索引
(a,b)可避免额外排序
错误的顺序可能导致索引“建了却用不上”,比如
(create_time, category_id)在按 category_id 精确查询时基本无效,换成
(category_id, create_time)就能覆盖更多场景。
联合索引比多个单列索引更省又更有效
对比单独建
INDEX(a)、
INDEX(b)、
INDEX(c): ✅ 联合索引
(a,b,c)可同时服务 a、a+b、a+b+c 查询,且只占一份存储空间 ✅ 写入时只需维护一个索引结构,减少 INSERT/UPDATE/DELETE 的开销 ❌ 多个单列索引无法协同加速多条件查询(优化器通常只选其一),还会加剧磁盘和内存压力 ⚠️ 注意宽度:一般建议不超过 3 列,列太多会让索引页变大、树变深,反而降低效率
本质上,联合索引是对查询模式的精准建模——建得准,才压得住慢 SQL。
