mysql如何创建合适的索引_mysql设计优化方法

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

WHERE 条件字段没索引,查询直接变慢

MySQL 不会自动给 WHERE 中的字段建索引,哪怕你频繁用

user_id
status
过滤。没索引时,每次查询都可能触发全表扫描,尤其当表超过 10 万行,响应时间就明显抖动。

实操建议:

EXPLAIN SELECT ...
type
是否为
ALL
(全表扫描),
key
列是否为
NULL
单列查询优先建单列索引:
CREATE INDEX idx_user_id ON orders(user_id);
多条件组合查询(如
WHERE category = ? AND status = ? AND created_at > ?
),按「过滤性高 → 等值 → 范围」顺序建联合索引,例如:
CREATE INDEX idx_cat_status_time ON orders(category, status, created_at);
避免在索引列上做函数操作,比如
WHERE YEAR(created_at) = 2024
会让索引失效;改用范围写法:
created_at >= '2024-01-01' AND created_at 

ORDER BY 和 GROUP BY 没走索引,临时表+文件排序很伤

ORDER BY
字段不在索引覆盖范围内,MySQL 可能创建内部临时表并进行 filesort,内存不够时还会写磁盘,性能断崖式下跌。

实操建议:

联合索引天然支持最左前缀的排序,比如已有
INDEX idx_a_b_c (a,b,c)
,那么
ORDER BY a,b
ORDER BY a,b,c
可走索引;但
ORDER BY b,c
就不行
GROUP BY
同理,尽量让分组字段匹配索引最左部分;若还需聚合后排序,把排序字段也纳入索引尾部,例如:
GROUP BY user_id ORDER BY created_at DESC
→ 建
INDEX idx_user_created (user_id, created_at)
确认是否用了
Using filesort
Using temporary
:执行
EXPLAIN FORMAT=TRADITIONAL
查看
Extra

索引太多或太宽,写入和维护成本反超收益

每加一个索引,INSERT/UPDATE/DELETE 都要同步更新 B+ 树,索引列越多、越长(比如

VARCHAR(500)
),B+ 树层级越深、页分裂越频繁,反而拖慢写操作。

实操建议:

单个索引字段数别超 3 个,字符串字段优先用前缀索引:
INDEX idx_title_prefix (title(10))
(前提是前 10 字节足够区分)
删除长期不用的索引:查
information_schema.STATISTICS
或用
sys.schema_unused_indexes
(MySQL 8.0+)
区分「高频读 + 低频写」和「高频写」表——后者索引要更克制,宁可加缓存也不盲目加索引 注意隐式类型转换导致索引失效,比如
user_id
BIGINT
,但 SQL 中传了字符串
'123'
,MySQL 可能放弃索引做全表转换

覆盖索引没利用好,回表成性能瓶颈

当查询字段都在索引中(比如

SELECT user_id, status FROM orders WHERE user_id = 123
),MySQL 可直接从索引 B+ 树叶子节点取值,无需回主键索引查整行——这就是覆盖索引。否则要先查索引定位主键,再用主键查聚簇索引,I/O 翻倍。

实操建议:

对高频查询语句,把
SELECT
中的字段尽可能塞进联合索引末尾,例如常用
SELECT id, user_id, status, amount
,WHERE 用
user_id
,可建:
INDEX idx_user_cover (user_id, id, status, amount)
注意主键自动包含在二级索引中,所以
SELECT user_id, id
INDEX idx_user (user_id)
上已是覆盖查询
别为了覆盖而覆盖:加太多冗余字段会让索引体积暴涨,评估时对比
data_length
index_length
(查
SHOW TABLE STATUS
索引不是越多越好,也不是建了就生效;真正关键的是理解查询模式、看清执行计划、持续验证效果。很多慢查问题其实卡在「以为走了索引,实际没走」或者「走了索引但回表太重」,而不是索引本身的设计。

相关推荐