一句话定义
联合索引(Composite Index)是把多个列按声明顺序拼成排序键的 B+ 树:它像字典先按首字母、再按次字母排序一样服从最左前缀原则,索引列顺序与查询列顺序必须同构才能被利用。
为什么重要
- 「建了索引却没用上」的线上慢查询,一多半败在对最左前缀与列顺序的误解。
- 正确的联合索引常能用一棵树替代多棵单列索引: fewer 索引 = 更低写放大 + 更高缓存命中。
- 覆盖索引与索引下推是「不回表」的两把钥匙,直接决定分页深、筛选严的查询性能。
前置知识
kp-009(B+ 树、回表、扇出)。
核心概念
- 最左前缀原则:索引
(a, b, c)可服务a、a,b、a,b,c的等值条件与a的范围条件,不能直接服务b或b,c。 - 列顺序设计:等值列在前、范围列在后;选择性高的等值列优先。
- 覆盖索引(Covering Index):查询所需列全部在索引内,Extra 出现
Using index,零回表。 - 索引下推(Index Condition Pushdown,ICP):把 WHERE 中索引列条件下推到存储引擎层过滤,减少回表行数。
- 索引跳跃扫描(MySQL 8 Skip Scan):前导列基数低时,优化器可为缺失前导列的查询枚举前导值。
- 前缀索引:长文本列只取前 N 字符建索引,牺牲选择性换空间。
原理与机制
联合索引 (a,b,c) 的排序规则是字典序:先按 a 排、a 相同再按 b、b 相同再按 c。于是「只知道 b 的范围」时树无法定位起点——区间信息从根到叶都依附于 a 的有序性,这就是最左前缀失效的机制本质。设计流程:把等值条件的列放前(各列均可整树定位),范围条件列放最后(范围列之后的列在树中不再有序,只能过滤)。若把范围列放中间,其后列的索引能力被截断。覆盖索引则是把 SELECT 列表也纳入索引(或利用 InnoDB 二级索引自带主键的特性),使整棵查询在索引内闭环;索引下推在 MySQL 5.6 后默认开启,让 (a,b) 索引在 a=x AND b>y 时先在叶子上滤掉 b 不满足的行再回表,回表行数从「a 命中数」降到「a∧b 命中数」。
实例或案例
订单表高频查询:WHERE user_id = ? AND status = 'paid' ORDER BY created_at DESC LIMIT 20。设计索引 (user_id, status, created_at):前两列等值定位、第三列在等值前缀内天然有序,ORDER BY 免排序直接取前 20 行;若 SELECT 只取 order_id(二级索引叶子自带主键)则完全覆盖。对照错误设计 (created_at, user_id, status):按时间排序的树上 user_id 无序,等值条件只能全索引扫描——列顺序颠倒,性能差几个数量级。
常见误区
- 给每列各建单列索引就以为万事大吉:多条件查询多数引擎只能用好其中一个索引再回表/合并,联合索引才是正解。
- 认为
WHERE b = ?用不了(a,b)就必须再建(b):低基数前导列可先试 MySQL 8 的跳跃扫描;PostgreSQL 也有类似规划器能力,先看执行计划再补索引。 - 索引列上套函数或隐式转换:
WHERE DATE(created_at) = '2026-10-01'、字符串列与数字比较都会使索引失效,应改为范围写法。
自测题
- 查询
WHERE a = ? AND c = ?能否用(a,b,c)?b起什么作用? 答:a 与 c 可用,但 c 无法直接定位(中间断了 b),只能在 a 命中的行内过滤;若 b 基数低可尝试跳跃扫描,否则考虑(a,c)。 - 什么叫「范围列放最后」?为什么? 答:等值列放前、范围列放索引末位;因为范围之后的列在树中失去有序性,继续放前面会截断其后列的定位能力。
公式或模型
回表行数估算(独立性假设):命中行 ≈ N × Π sel(col_i);ICP 后回表 ≈ N × sel(a) × sel(b)。覆盖索引收益 ≈ 省去 命中行 × 1 次聚簇索引随机读。
图示
本节不适用:字典序逻辑用「电话簿先姓后名」的类比与案例已可自验,画排序矩阵的增益低于成本。
直观类比
联合索引就是电话簿:先按姓排、同姓按名排。你问「所有姓王的人」很好翻(最左前缀);问「所有叫强的人」就得翻遍全簿(跳过姓无法定位)。把「省份、城市、下单时间」按此规则排好,找「杭州十月一日以来的订单」一翻一个准。
与其他知识点的关系
kp-009 提供树结构与回表机制;kp-012 用 EXPLAIN 验证本篇设计是否生效;kp-029 汇总索引失效类反模式;kp-013 解释优化器如何评估多个候选索引。
延伸阅读
- 《高性能 MySQL》(Baron Schwartz 等)索引章节
- MySQL 官方文档「Range Optimization / Index Condition Pushdown」章节(以本地手册核对为准)