联合索引(a,b,c)是一棵按a→b→c顺序排序的单棵B+树,必须从最左列a开始连续匹配,跳过a则无法定位起点,故WHERE b=2等查询无法使用索引。

联合索引不是“多个字段拼一起”,而是有严格顺序的B+树结构
MySQL的联合索引 (a, b, c) 不是把三列值简单拼成字符串存起来,而是按列顺序构建一棵B+树:先按 a 排序;a 相同再按 b 排序;a 和 b 都相同才按 c 排序。这意味着树的层级天然由左到右展开,跳过前面的列,后面列就失去组织依据。
所以不是“只要字段在索引里就能用”,而是“必须从最左开始连续可用”。比如 WHERE b = 1 AND c = 2 完全无法利用 (a, b, c) 索引——a 没出现,整棵树没入口,只能全表扫描。
WHERE a = 1 AND c = 2 能走索引,但只用上 a
这个查询看似“跳过了 b”,实际会走索引,但仅限于定位 a = 1 对应的数据页范围。之后的 c = 2 过滤发生在引擎层(Index Condition Pushdown,ICP),即在读取索引节点时顺便判断 c 值,避免回表后才过滤。但这不等于 c 参与了索引查找——b 列仍被完全跳过,c 无法加速定位。
- MySQL 5.6+ 支持 ICP,
c的过滤可下推到存储引擎层 - MySQL 5.6 之前,
c过滤只能在 Server 层做,效率更低 - 无论是否 ICP,
b列始终不参与索引匹配过程
范围查询(>、<、BETWEEN、LIKE 'abc%')会让右侧所有列失效
一旦某列用了范围条件,它右边的所有列就彻底退出索引匹配。例如索引 (a, b, c),查询 WHERE a = 1 AND b > 10 AND c = 100 中,c 无法用于索引查找——因为 b > 10 返回的是一个区间,c 在该区间内无序,无法继续二分查找。
常见误区是认为“c 也有等值条件,应该能用”。错。B+树只保证 (a, b, c) 全序,不保证 (a, b>10, c) 有序。此时索引只用到 a 和 b,c 是纯过滤项。
-
LIKE 'xxx%'是范围(前缀匹配),LIKE '%xxx'是全模糊,二者都不触发最左匹配 -
IS NULL、IS NOT NULL视为等值条件,不影响后续列匹配 -
!=或<>也属于范围类操作,同样截断匹配
SQL写法顺序无关,但字段选择和索引定义顺序至关重要
WHERE b = 1 AND a = 1 和 WHERE a = 1 AND b = 1 效果一样——优化器会自动重排条件顺序。真正起决定作用的是:查询中实际出现的字段集合,以及这些字段在索引中的定义位置。
容易忽略的一点是:即使所有字段都出现在 WHERE 中,如果索引定义顺序不合理,依然会浪费。例如高频查询是 WHERE city = ? AND age = ?,却建了 (age, city) 索引,那 city 就永远只是“被跳过的中间列”,无法发挥价值。
- 建索引前先看
EXPLAIN输出的key_len,它能告诉你实际用了索引前几列 - 区分度高的列(如
user_id)放左边不一定最优,得结合查询模式——等值多的放左,范围多的靠右 - 不要迷信“把所有WHERE字段塞进一个联合索引”,冗余索引反而拖慢写性能


















