mysql如何为查询语句设计索引_mysql索引设计思路

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

WHERE 条件字段必须是索引的最左前缀

MySQL 的 B+ 树索引生效依赖「最左前缀匹配」,不是 WHERE 里出现的字段就自动能走索引。比如有复合索引

INDEX idx_user_status_created (user_id, status, created_at)
,以下查询能用上索引:

WHERE user_id = 123
WHERE user_id = 123 AND status = 'active'
WHERE user_id = 123 AND status = 'active' AND created_at > '2024-01-01'

但这些不行:

WHERE status = 'active'
(跳过
user_id
,无法命中)
WHERE created_at > '2024-01-01'
(完全不满足最左前缀)
WHERE status = 'active' AND created_at > '2024-01-01'
(缺少
user_id

执行前务必用

EXPLAIN
key
possible_keys
是否匹配预期,别凭感觉。

避免在索引列上做计算或函数操作

对索引字段使用函数、表达式或类型转换,会直接导致索引失效。常见踩坑点:

WHERE YEAR(created_at) = 2024
→ 改成
WHERE created_at >= '2024-01-01' AND created_at 
WHERE UPPER(name) = 'JOHN'
→ 改成建函数索引(MySQL 8.0+):
CREATE INDEX idx_name_upper ON users ((UPPER(name)))
,或统一存大写
WHERE age + 1 > 30
→ 改成
WHERE age > 29

注意:MySQL 8.0 支持函数索引,但低版本只能靠冗余字段或改写条件。

ORDER BY 和 GROUP BY 要尽量复用索引顺序

如果查询含

ORDER BY a, b
,而索引是
(a, b, c)
,就能避免 filesort;但如果索引是
(b, a)
(a, c, b)
,就无法覆盖排序需求。

同样,

GROUP BY
也遵循最左前缀,且要求顺序一致。例如:

SELECT user_id, COUNT(*) FROM orders GROUP BY user_id, status;

对应索引应为

INDEX idx_user_status (user_id, status)
,而非
(status, user_id)
—— 后者可能触发临时表 + filesort。

如果

ORDER BY
DESC
,MySQL 8.0+ 支持在索引中显式声明方向:
INDEX idx_created_desc (created_at DESC)
;5.7 及以前,混合 ASC/DESC 会退化为 filesort。

区分等值查询和范围查询的位置

在复合索引中,**等值条件(=、IN)应放在范围条件(>、

例如索引

(a, b, c)

WHERE a = 1 AND b > 10 AND c = 5
c
不会走索引(
b
是范围,中断了最左前缀)
WHERE a = 1 AND c = 5 AND b > 10
→ 同样无效,顺序不影响解析逻辑,MySQL 按索引定义顺序匹配
正确设计应把高频等值字段前置,范围字段放最后,如
(a, c, b)
适配
a = ? AND c = ? AND b > ?

实际建索引前,先用

SELECT DISTINCT
或慢日志分析字段的过滤选择性,高选择性字段(如
user_id
)比低选择性字段(如
status
,只有 active/inactive)更适合放前面。

索引不是越多越好,每多一个索引都增加写开销和内存占用。重点盯住慢查询日志里的

Rows_examined
和执行计划中的
type
(至少到
range
,最好
ref
const
)。真正难的是平衡多条语句的索引诉求——一条语句想要
(a,b)
,另一条想要
(b,c)
,这时候得权衡冗余索引还是拆分查询。

相关推荐