联合索引底层是b+树,最左前缀原则由其物理结构决定:索引(a,b,c)按a全局排序、a相同时按b排序、a和b都相同时按c排序,故查询必须从a开始连续匹配,跳过左侧字段则右侧字段无法定位。

联合索引底层是B+树,不是“规则”而是物理结构限制
最左前缀原则不是MySQL的语法约定或优化器策略,而是InnoDB引擎中B+树索引的物理存储方式决定的。索引 (a, b, c) 对应一棵按字典序排序的B+树:先全局按 a 排序;a 相同时,再按 b 排序;a 和 b 都相同时,再按 c 排序。这意味着,没有确定 a 的取值范围,b 和 c 在整棵树里是无序的。
所以,WHERE b = 2 这类查询无法跳过 a 直接定位——就像查电话簿,不指定姓氏(a),只凭名字(b)或年龄(c)根本没法二分查找。
WHERE 条件顺序不影响索引匹配,但字段是否出现和类型决定能用几列
MySQL优化器会自动重排 WHERE 子句中的条件顺序,WHERE b = 2 AND a = 1 和 WHERE a = 1 AND b = 2 效果完全一致,都能用上 (a, b) 段。
-
WHERE a = 1→ 可用a列(等值,精准定位分组) -
WHERE a = 1 AND b = 2→ 可用a, b(组内再二分) -
WHERE a = 1 AND c = 3→ 仅用a,c在叶子节点做ICP过滤,不加速定位 -
WHERE a > 1 AND b = 2→ 仅用a,b = 2同样退化为ICP
范围查询(>、、<code>BETWEEN、LIKE 'abc%')会“截断”索引链
一旦某列使用了范围查询,它右侧所有列都失去索引定位能力,只能靠ICP在已读取的索引页内过滤。这不是bug,是B+树结构的自然结果:范围扫描 a > 1 会拉出多个 a 分组,每个分组内 b 虽然有序,但跨分组后整体无序,无法再对 b 做高效跳转。
示例索引 idx_status_time_user(status, create_time, user_id):
-
WHERE status = 1 AND create_time > '2024-01-01'→status和create_time参与定位,user_id不参与 -
WHERE status > 1 AND user_id = 100→ 仅status参与定位,user_id完全无法用于缩小搜索范围
容易被忽略的关键点:索引不是“开关”,而是“分段可用”
很多人误以为“没走索引”或“走了索引”是非黑即白。实际上,联合索引的使用是分层的:(a, b, c) 索引在 WHERE a = 1 AND c = 3 下依然“走了”,只是只用了第一段 (a),c 部分不提升定位效率,只减少回表数据量(如果覆盖查询则可能免回表)。真正要警惕的是跳过最左列(如只查 b 或 c),这时才会触发全表扫描。
验证时别只看 key 字段是否非NULL,重点看 key_len 和 rows:前者告诉你实际用了索引前几列,后者暴露扫描基数是否失控。











