联合索引设计与最左前缀原则

kp-011 · 索引与查询优化核心约 25 分钟已校对

前置知识点

前置:

相关知识点

相关:

学习进度:

一句话定义

联合索引(Composite Index)是把多个列按声明顺序拼成排序键的 B+ 树:它像字典先按首字母、再按次字母排序一样服从最左前缀原则,索引列顺序与查询列顺序必须同构才能被利用。

为什么重要

前置知识

kp-009(B+ 树、回表、扇出)。

核心概念

原理与机制

联合索引 (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 无序,等值条件只能全索引扫描——列顺序颠倒,性能差几个数量级。

常见误区

自测题

  1. 查询 WHERE a = ? AND c = ? 能否用 (a,b,c)?b 起什么作用? 答:a 与 c 可用,但 c 无法直接定位(中间断了 b),只能在 a 命中的行内过滤;若 b 基数低可尝试跳跃扫描,否则考虑 (a,c)。
  2. 什么叫「范围列放最后」?为什么? 答:等值列放前、范围列放索引末位;因为范围之后的列在树中失去有序性,继续放前面会截断其后列的定位能力。

公式或模型

回表行数估算(独立性假设):命中行 ≈ N × Π sel(col_i);ICP 后回表 ≈ N × sel(a) × sel(b)。覆盖索引收益 ≈ 省去 命中行 × 1 次聚簇索引随机读。

图示

本节不适用:字典序逻辑用「电话簿先姓后名」的类比与案例已可自验,画排序矩阵的增益低于成本。

直观类比

联合索引就是电话簿:先按姓排、同姓按名排。你问「所有姓王的人」很好翻(最左前缀);问「所有叫强的人」就得翻遍全簿(跳过姓无法定位)。把「省份、城市、下单时间」按此规则排好,找「杭州十月一日以来的订单」一翻一个准。

与其他知识点的关系

kp-009 提供树结构与回表机制;kp-012 用 EXPLAIN 验证本篇设计是否生效;kp-029 汇总索引失效类反模式;kp-013 解释优化器如何评估多个候选索引。

延伸阅读