mysql索引对写入性能有什么影响_mysql读写权衡解析

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

索引越多,INSERT/UPDATE/DELETE 越慢

每新增一条记录或修改带索引的字段时,MySQL 不仅要写数据页,还要同步更新所有相关索引的 B+ 树结构。这意味着:

INSERT
每多一个二级索引,就要多一次随机磁盘写(或缓冲池刷脏);
UPDATE
若修改了索引列,可能触发索引项删除 + 重建;
DELETE
则需在每个索引中定位并移除对应条目。

常见错误现象包括:

批量导入 10 万行数据,加了 5 个二级索引后耗时从 2 秒涨到 47 秒
UPDATE user SET status = 1 WHERE id = 123
很快,但改成
UPDATE user SET email = 'x@y.z' WHERE id = 123
后变慢——因为
email
是唯一索引,需校验冲突

哪些索引对写入影响最大

影响程度取决于索引类型、是否唯一、以及字段更新频率。排序从高到低:

UNIQUE
索引:每次写入都必须做重复值校验,涉及索引查找 + 锁定范围,开销显著高于普通索引
长字符串字段上的索引(如
VARCHAR(500)
):B+ 树节点存储更多字节,导致页分裂更频繁,写放大更严重
频繁更新的列上的索引(如
updated_at
status
):每次
UPDATE
都触发索引维护
复合索引中靠前的列若常被更新,整条索引项都要挪动;靠后的列更新则影响小得多

如何在读写间做实际取舍

没有通用最优解,但可按以下原则快速判断:

先用
EXPLAIN
确认查询真正在用哪个索引,避免“以为有用其实没走”的假索引
对写入密集型表(如日志、消息队列),优先保留
PRIMARY KEY
和极少数高频
WHERE
条件索引,其余改用应用层缓存或异步聚合查询
批量写入前临时禁用非必要索引(仅限
MyISAM
InnoDB
不支持,但可用
DROP INDEX
+
ADD INDEX
替代,注意锁表时间)
innodb_change_buffering = all
(默认)让插入/更新的二级索引变更先缓存在内存,减少随机 IO —— 但会增加缓冲池压力,且崩溃后需重放 change buffer
SHOW VARIABLES LIKE 'innodb_change_buffering';

容易被忽略的隐性成本

索引不仅拖慢写入,还会悄悄吃掉更多资源:

每个索引都占用
ibdata1
或独立表空间,备份体积和恢复时间线性增长
SELECT COUNT(*)
在无
WHERE
时,InnoDB 必须遍历主键或某个索引——如果只有大字段的二级索引,反而比全表扫还慢
很多 ORM 自动生成的“防错索引”(如给所有外键加索引)并无真实查询支撑,纯属冗余
ANALYZE TABLE
会重新采样索引统计信息,索引越多,采样越久,期间可能阻塞 DML

真正需要权衡的从来不是“要不要索引”,而是“这个索引有没有被稳定、高频、不可替代地用到”。

相关推荐