复合索引遵循最左前缀原则,即where条件必须从索引最左列开始连续匹配才能生效;order by/group by需与索引前缀顺序一致才可避免排序;覆盖索引要求select字段全在索引中以避免回表。

复合索引的最左前缀原则怎么生效
MySQL 的 WHERE 条件只有从复合索引最左边列开始连续匹配时,才能用上索引。比如建了 (a, b, c) 的联合索引,WHERE a = 1 AND b = 2 可以走索引;WHERE b = 2 AND c = 3 完全无法使用该索引。
常见错误是以为只要条件里有索引字段就能命中——实际必须满足“连续、从左开始”。如果查询只用 c,哪怕 a 和 b 都是常量值(如 WHERE a = 1 AND b = 1 AND c = 3),仍能走索引;但一旦跳过 a 或 b,就失效。
-
WHERE a = 1✅ 走索引 -
WHERE a = 1 AND b > 2✅ 走索引(b用于范围扫描,c不再参与) -
WHERE a = 1 AND c = 3⚠️ 只能利用a,c不生效(b缺失导致断层) -
WHERE b = 2❌ 不走索引
ORDER BY 和 GROUP BY 如何复用复合索引
当 ORDER BY 或 GROUP BY 字段顺序与复合索引前缀完全一致时,可避免额外排序(Using filesort)。例如索引为 (user_id, status, created_at),则 ORDER BY user_id, status 可免排序;但 ORDER BY status, created_at 就不行。
注意:ASC/DESC 混用在 MySQL 8.0 之前会导致整个排序无法利用索引(8.0+ 支持混合方向,但需显式定义索引方向)。
- 索引
(a, b, c)→ORDER BY a, b✅ 免排序 - 索引
(a, b, c)→ORDER BY a DESC, b ASC❌ 8.0 前不支持,会触发Using filesort - 索引
(a ASC, b DESC)→ORDER BY a ASC, b DESC✅(仅限 MySQL 8.0+)
SELECT 列是否影响复合索引选择性
复合索引本身不直接决定 SELECT 返回哪些列,但若所有查询字段都包含在索引中(即覆盖索引),MySQL 就不必回表查主键行,性能显著提升。例如表有 id, name, email, age,查询 SELECT name, email FROM t WHERE age = 25,若建索引 (age, name, email),就能覆盖查询。
但要注意字段顺序:用于过滤的列(如 age)应放最左,其他返回字段按查询频率或长度排布(短字段优先可略微减少索引体积)。
- 覆盖索引可避免
Using where; Using index中的回表开销 - 不要把大字段(如
TEXT、长VARCHAR)塞进索引,可能拖慢写入且收益低 -
SELECT *几乎不可能被覆盖,除非索引包含所有列(不推荐)
EXPLAIN 看懂 key_len 和 Extra 判断是否真用对了
key_len 显示 MySQL 实际用了索引的多少字节,是判断是否遵循最左前缀的关键依据。比如 utf8mb4 字符集下 VARCHAR(50) 最大占 200 字节(50×4),若 key_len = 200,说明只用了第一个字段;若 key_len = 202,可能第二个字段是 TINYINT(1 字节)+ NULL 标志(1 字节)。
Extra 中出现 Using index condition 表示用了 ICP(索引下推),即部分 WHERE 条件在存储引擎层过滤;而 Using index 才表示真正覆盖索引;Using where 通常意味着回表后还需 Server 层过滤。
- 看到
key_len远小于索引总长度,大概率没用全索引 -
Extra: Using index; Using where≠ 覆盖索引,而是索引覆盖 + 回表后二次过滤 - 联合索引中含
NULL列时,每个字段多占 1 字节,会影响key_len计算
(a,b,c,d) 却只查 a 和 d,结果 d 彻底闲置——这时候不如拆成两个更窄的索引,或者重排顺序。索引设计必须跟着 EXPLAIN 走,而不是凭感觉。










