索引拖慢数据库写入,3种情况最常见

索引拖慢数据库写入,3种情况最常见——这话听着像在给索引甩锅,可线上真就经常是这样。插一条记录进去,应用那边要排队等,磁盘灯闪得并不凶,CPU 也闲着,监控上唯一难看的就是写入延迟。不少人第一反应是换 SSD、加内存、升配置,钱花出去了问题还在原地。索引这东西,读的时候是加速器,写的时候就是一笔额外的账:每写一行数据,表上挂了几个索引,就得跟着记几笔,一个都跑不掉。

写入性能

索引拖慢数据库写入3种情况最常见,先别急着换硬件

想弄明白为什么慢,得先知道一条 insert 在索引上到底做了什么。数据库要先找到这条记录该插在哪一页,然后维护 B+ 树的结构,如果表上有唯一索引,还得先查一遍有没有重复值,页装满了就分裂出新页,这些动作大多不是顺序写。所以索引数量、索引字段的分布、写入的批次大小,直接决定了一条写入到底是几毫秒还是几十毫秒的事。硬件当然有影响,但它往往不是第一嫌疑人。

第一种:写多读少的表,索引挂得太随意

日志表、流水表、埋点表、消息记录表,这类表天生就是写多读少。可现实里它们身上的索引经常最多,因为开发阶段为了查数据方便,见个字段就加一条,上线之后没人回头清理。查是查得舒服了,写入端每条记录都要多维护好几棵树。这类表最该做的是把索引压到最低,只留业务真正会用的那几条,剩下的靠临时查询、离线库或者日志平台去解决。一个字段值重复度极高、单独查出来几十万行的索引,留在写入频繁的表上基本就是负担。

第二种:联合索引顺序随手排,冗余索引互相压着

联合索引的顺序不是随便写的。(a,b) 和单独的 (a) 同时存在,前者已经把后者的活干了,后者就是白交的写入成本。还有一种是拿状态、类型这种低区分度字段打头,看着查询能命中,实际上维护成本一点没少。另外要留意唯一索引,插入时的唯一性校验得先把相关页读进来,碰上缓冲池没命中就是一次随机读。索引建得越密,写入路径上要碰的页就越多,缓冲池里塞的索引页也越多,脏页刷盘的节奏跟着变乱,连锁反应一串一串的。

第三种:批量导入的时候,索引全程开着

这条踩的人最多。几万条数据往一张空表里灌,很多人直接循环一条条插,每插一条维护一遍全部索引,页分裂、随机 IO 全来了,导入时间能比预期长出一大截。更稳的做法是分批提交、按主键顺序灌、导入前先把非必需的二级索引删掉,数据进去了再重建——重建索引是一次顺序扫描,比边插边维护划算得多。顺便提一句,网上常见的 ALTER TABLE … DISABLE KEYS 对 MyISAM 有效,InnoDB 上别指望它,具体行为以所用版本的官方文档为准,别照抄老帖子。

怎么确认问题真出在索引身上

别猜。先把慢查询日志和 performance_schema 里按语句摘要统计的耗时翻出来,看看慢的是不是集中在 insert、update、replace 上;再去看表结构,用 sys.schema_redundant_indexes 或者 percona-toolkit 里的索引分析工具扫一遍,冗余和重复的索引会直接列出来。想验证更简单:拿一批测试数据,在同一个库上做一次删索引前后的导入对比,差距一眼就能看出来。系统层面再看 iostat 的 await 和 fsync 频率,如果磁盘忙但吞吐不高,多半就是随机写被索引放大了。

能马上动手的几件事

先把线上每张写频繁的表过一遍索引清单,找出前缀重复的、从没被查询命中过的、区分度低到没意义的,该删就删,删之前确认没有查询依赖;写多读少的表给索引数量定个上限,新加索引走评审;批量导入一律改成分批加顺序写,量大就考虑先删二级索引再重建;主键尽量用自增或者趋势递增的值,随机字符串主键在写入上一直不占便宜。至于那些 innodb 缓冲池、刷盘策略之类的参数,属于最后再动的手段,改之前备份、查官方说明,别在业务高峰试。

回到最开始那句话,写入慢不等于机器不行。把索引数清楚、把写入路径理一遍,很多问题不用花钱就能解决一部分。真正难的不是调参数,是忍住那种“先加个索引试试”的冲动。

【版权声明】:本站内容若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!

赞 (0)
爱家的头像爱家
开源项目网站,官方仓库还是第三方聚合
上一篇 2026-10-27 18:47
笔记本无法光盘启动该怎么办,是不是BIOS引导顺序问题?
下一篇 2025-10-02 09:19

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

广告合作

QQ:14239236

在线咨询: QQ交谈

邮件:asy@cxas.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信