mysql索引列的顺序如何确定_mysql索引优化技巧

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

WHERE 条件中字段的出现顺序决定索引列顺序

MySQL 的 B+ 树索引是按定义顺序逐列比较的,

WHERE a = 1 AND b = 2 AND c > 3
这类查询,只有把
a
放在索引最左,才能用上整个索引。如果索引是
(b, a, c)
,那
a
就无法走最左前缀,只能用到
b
那一列(前提是
b
有等值条件)。

实操建议:

把等值查询(
=
IN
)字段放前面,范围查询(
>
BETWEEN
LIKE 'abc%'
)放后面
如果多个字段都是等值查询,把区分度高(基数大)的字段放更左,比如
user_id
status
更适合作为第一列
避免把经常单独查的低频字段放在最左,否则其他组合查询可能用不上这个索引

ORDER BY 和 GROUP BY 字段必须紧接在 WHERE 等值条件之后

MySQL 只有在索引能“覆盖”排序或分组时,才避免额外的 filesort 或 temporary table。例如

SELECT * FROM t WHERE a = 1 ORDER BY b, c
,索引
(a, b, c)
可以复用;但若写成
(a, c, b)
b
不在连续位置,就无法利用索引排序。

常见错误现象:

EXPLAIN
结果中
Extra
列出现
Using filesort
,说明排序没走索引
GROUP BY
后字段顺序和索引不一致,哪怕所有字段都在索引里,也可能触发临时表
混合 ASC/DESC(如
ORDER BY b ASC, c DESC
)在 MySQL 8.0 之前无法用索引排序,8.0+ 要求索引定义也显式声明方向

联合索引不是“字段集合”,重复建单列索引往往没用

有联合索引

(a, b, c)
,它天然包含
(a)
(a, b)
的能力,但不包含
(b)
(c)
单独查询的能力。此时再单独建
INDEX(b)
,不是补充,而是冗余——除非你真有高频的
WHERE b = ?
查询且无法改写 SQL。

性能与维护影响:

每个索引都增加写开销(INSERT/UPDATE/DELETE 都要更新索引树) 索引占用磁盘和内存,过多索引会拖慢 buffer pool 命中率
SHOW INDEX FROM table_name
查看
Cardinality
,长期为 0 或极低的索引值得删掉

WHERE 中用了函数或表达式,索引直接失效

WHERE YEAR(create_time) = 2023
WHERE phone LIKE '%138%'
(左侧通配),MySQL 无法用索引定位,因为索引存的是原始值,不是计算结果。

可选替代方案:

把函数移到右边:
create_time >= '2023-01-01' AND create_time 
对固定前缀模糊查,用
LIKE '138%'
,它能走索引;但
LIKE '%138'
LIKE '%138%'
不行
实在要函数查询,考虑生成列(generated column)+ 函数索引(MySQL 5.7+):
ALTER TABLE t ADD COLUMN y INT AS (YEAR(create_time)) STORED, ADD INDEX idx_y(y)

真正容易被忽略的是:索引优化不能只看单条 SQL,得看整体查询模式。一个

(a, b, c)
索引可能让三条不同 WHERE 条件的查询受益,也可能因其中一条查
c
单独出现而完全浪费。上线前用
pt-query-digest
或 slow log 统计真实查询分布,比凭经验猜更可靠。

相关推荐