mysql中索引字段的选择与查询性能提升

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

WHERE 条件里用到的字段必须建索引

查询慢,八成是因为

WHERE
子句里的字段没加索引。MySQL 只能走全表扫描,数据量一过万,响应就明显卡顿。

比如执行

SELECT * FROM orders WHERE user_id = 123;
,但
user_id
没索引,哪怕加了
LIMIT 1
也无济于事——优化器不知道你能快速定位,照样扫全表。

单列查询优先建单列索引:
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
多个字段常一起出现在
WHERE
中(如
WHERE status = 'paid' AND created_at > '2024-01-01'
),考虑联合索引,注意字段顺序:等值条件字段放前,范围条件字段放后(
status
是等值,
created_at
是范围,所以联合索引应为
(status, created_at)
ORDER BY
字段如果和
WHERE
字段不重合,且排序量大,也建议覆盖进联合索引,避免额外排序(filesort)

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

一旦对索引字段使用函数、类型转换或表达式,索引就失效。这是线上最常见却最容易被忽略的性能陷阱。

例如:

WHERE YEAR(created_at) = 2024
WHERE UPPER(name) = 'JOHN'
,即使
created_at
name
有索引,也无法命中。

改写为范围查询:
WHERE created_at >= '2024-01-01' AND created_at 
区分大小写需求可用校对规则替代:
name COLLATE utf8mb4_0900_as_cs = 'John'
(前提是建索引时用了对应 collation)
模糊查询慎用前导通配符:
LIKE '%abc'
必定走全表;
LIKE 'abc%'
可走索引

索引不是越多越好:维护成本与写入延迟

每多一个索引,INSERT / UPDATE / DELETE 就得多维护一份 B+ 树结构。高并发写入场景下,索引过多会显著拖慢写性能,甚至引发锁竞争。

尤其要注意:

TEXT
BLOB
字段不能直接建索引;长字符串字段(如
VARCHAR(500)
)建索引要指定前缀长度,否则可能超出限制或浪费空间。

SHOW INDEX FROM table_name;
定期检查未被使用的索引(配合
performance_schema.table_io_waits_summary_by_index_usage
复合索引中重复包含其他索引的左侧字段,大概率冗余。例如已有
(a, b)
,再建
(a)
就没必要
主键本身就是聚簇索引,不要在主键字段上再额外建普通索引

EXPLAIN 是唯一可信的判断依据

别猜,别依赖“应该走了索引”。每次加完索引,必须用

EXPLAIN
看实际执行计划。重点看
type
(至少到
range
,理想是
ref
const
)、
key
(是否命中预期索引)、
rows
(预估扫描行数)和
Extra
(警惕
Using filesort
Using temporary

EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

如果

key
为空,或者
rows
接近表总行数,说明索引没生效——这时候得回溯前面三条:字段是否参与了计算?联合索引顺序对不对?WHERE 条件是否覆盖了最左前缀?

真实业务里,索引效果受数据分布影响极大。比如某个字段只有两个取值(

status
'active'
/
'inactive'
),即使建了索引,优化器也可能直接放弃使用——因为走索引再回表,不如全表扫描快。这种时候,要么加过滤条件缩小结果集,要么考虑分区或物化视图方案。

相关推荐