复合索引的最左前缀原则怎么生效
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走,而不是凭感觉。
