mysql如何使用复合索引提高查询效率_mysql联合索引分析

来源:这里教程网 时间:2026-02-28 20:49:28 作者:

复合索引的最左前缀原则怎么生效

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
走,而不是凭感觉。

相关推荐