联合索引底层是b+树,只能按最左字段排序;索引(a,b,c)中a为最左前缀,缺失a则无法定位数据分组,跳过a或a为范围查询时右侧字段索引失效。

联合索引底层是B+树,只能按最左字段排序
MySQL的InnoDB引擎所有索引都基于B+树,而联合索引(a, b, c)的物理结构是:先按a全局升序排列;a相等时,再按b升序;a和b都相等时,才按c升序。这就像电话簿——先按姓氏排,同姓再按名字排,同名再按年龄排。没有姓氏,就无法定位“张”这个大块,更没法在其中找“张三”。
WHERE条件跳过最左列,MySQL无法定位数据分组
查询WHERE b = 10 AND c = 20时,a未出现在条件中,MySQL不知道该去哪个a值的子树里找数据,只能扫描全部叶子节点,退化为全表扫描。
-
WHERE a = 5→ 能快速跳到a=5的整段分支 -
WHERE a = 5 AND b > 10→ 在a=5分支内用b二分查找起始点,但c因b是范围查询而失效 -
WHERE a = 5 AND c = 20→a生效,c无效(中间缺了b,B+树里c在a相同前提下才有序)
优化器会重排WHERE顺序,但不改变匹配起点
写成WHERE b = 10 AND a = 5,MySQL优化器会自动调整为a = 5 AND b = 10执行,所以字段顺序不影响是否命中索引。但前提是a必须出现——只要a在条件里,哪怕写在后面,也能走索引;一旦a完全没出现,再怎么重排也没用。
范围查询会切断右侧字段的索引能力
这是最容易被忽略的隐性陷阱。比如索引(status, created_at, user_id),查询WHERE status = 'done' AND created_at > '2024-01-01'时,user_id字段索引彻底失效。因为created_at > ...导致满足条件的记录在B+树中不再连续,user_id失去局部有序性,无法再用索引过滤。
真正影响性能的不是“写了多少条件”,而是“从哪一列开始断开有序链”。只要最左列存在且非范围,左侧连续字段就能用上;一旦遇到范围或不等号,右边全废。











