数据库索引:写入变慢是躲不掉的代价

索引不是白送的。你给表加一个索引,读的时候省了扫描,写的时候就得替它维护一棵树——数据库索引写入变慢是躲不掉的代价,问题只在于这个代价有多大、你能不能接受。指望调两个参数就把写入拉回建索引之前的水平,基本是做梦;真能明显改善的,往往是索引本身建得就不对,或者一批该合并的写被拆成了一条条提交。

写入变慢

数据库索引写入变慢是躲不掉的代价,先看这笔钱花在哪

一条 insert 进 InnoDB,落的不只是聚簇索引那一行。表上有几个二级索引,就得多改几棵树:定位叶子页、改记录、写 redo、把页标脏。页写满了还要分裂,一分裂就是两页的活,连带上层指针也要动。update 碰上被索引的列更麻烦,等于删一遍再插一遍,索引越多,重复动作越多。业内管这叫写放大,听着玄,拆开看就是一句话——一次业务写入,底下干了好几次活。

所以别把写入变慢当成故障。它是设计里明码标价的成本,只是账单不在建索引那天送到你手上,而是在数据量涨起来、并发上来之后才慢慢显形。

那就把索引全删了?读那边立刻还你颜色

走极端最省事也最蠢。索引删光的表,查询全表扫,扫描行数上去了,锁的时间和范围也跟着上去,一台机器上几个慢查询叠着跑,写入队列一样堵。要减的是没人用的索引和重复的索引,不是所有索引。

举个常见的:一个 (user_id, created_at) 的联合索引,很多时候比 user_id 单列加 created_at 单列两个索引加起来更划算——写的时候少维护一棵树,读的时候还能顺手覆盖排序。能不能真覆盖,拿 explain 看一眼,别凭感觉拍板。

主键乱序,是写入身上最隐蔽的一笔税

自增主键的插入基本都在最右边追加,页填充整齐,缓存也友好;换成随机字符串当主键,每次插都可能落到中间某个页,页分裂和缓存命中率下降跟着来,数据量越大越明显。业务上确实需要全局唯一标识,也尽量让它有序,或者把它当业务唯一键、主键仍旧用自增。这条不是理论,把一张写入量大的表从随机串主键改成自增,写延迟的变化通常肉眼可见,改之前先在测试库上比一比。

唯一索引和普通索引,写入时干的活不一样

唯一索引插入前要确认没有冲突,页不在内存里的时候也得把页读进来核对;普通二级索引宽松些,可以先记在 change buffer 里,等页被读上来时再合并。所以除非业务真的要求唯一,别顺手加 unique,尤其是那种“反正加了也不亏”的心态,亏在写入上。

change buffer 也不是免单。机器重启、刷脏、页被读上来的时候,账还是要还,它做的只是把尖峰摊平,让写入别在同一秒全砸到磁盘上。

批量写比调参管用,但别一口吃成胖子

一条一条 commit,每次都要等日志落盘,网络来回也白搭。把能合并的写合成一批,提交频率降下来,整体吞吐自然上去。但批次别无限放大:事务太大,undo 涨得快、锁持有时间长,真出问题时回滚也慢得难受。导入历史数据这种场景,临时调低刷盘频率确实快不少,代价是掉电可能丢掉最后一段事务,值不值自己衡量,参数的确切含义和影响以官方文档为准。

怎么确认慢在索引维护,而不是别的地方

别一上来就盯 CPU。iostat 看 util 和 await,写延迟高而 CPU 不高,多半是在等磁盘;show engine innodb status 里看有没有堆积的写和刷脏进度;performance_schema 里看是不是卡在锁等待或者行锁冲突。想找没用的索引,MySQL 的 sys 库里有现成视图,但它统计的是实例启动以来的使用情况,重启会清零,结论要结合业务周期看,别拿一小时的数据下结论。

几个容易踩的小地方

字符串列建索引给个前缀长度,把整列长文本塞进索引里,写入和存储两头吃亏;冗余索引最典型的是 (a) 和 (a,b) 同时存在,前者基本可以去掉;主从架构里主库的索引维护开销到从库还要再走一遍,回放延迟有时候就是这么攒出来的;还有统计信息的更新、函数索引、全文索引,都会在写入路径上多多少少掺一脚。

对了,别忽略大事务和长连接。有些写入慢根本不在索引身上,是一个事务开着不提交,把行锁攥了半天,后面排队的全在等。查索引之前先看看有没有这种钉子户。

真要动手,顺序大致是这样:先翻慢查询日志确认哪些索引确实在被用,再对着表结构找冗余和重复,然后检查主键是不是乱序,最后一档才去动批量提交和刷盘参数。反过来做也常见——参数先调一遍,该删的索引没删,过两天又慢回来,白折腾一场。写入性能这事没有一键方案,只有取舍。

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

赞 (0)
爱家的头像爱家
虚拟空间还是轻量云:三年账算下来差多少
上一篇 2026-11-02 02:13
如何搭建家庭FTTR服务器,实现真正的全屋光纤覆盖?
下一篇 2025-10-16 12:29

相关推荐

  • 如何备份MySQL中的指定数据库文件和实例?

    要备份MySQL中的指定数据库文件,您可以使用mysqldump命令。以下是备份名为your_database_name的数据库的示例:,,“bash,,mysqldump u your_username p your_database_name ˃ backup.sql,,`,,请将your_username和your_database_name替换为您的实际用户名和数据库名称。在执行此命令时,系统会提示您输入密码。备份文件将被保存为backup.sql`。

    2024-08-22
    0017
  • 电商网站建设咨询_哪些网站必须启用HTTPS加密?

    在当前网络环境下,HTTPS加密已经成为网站建设的标配,尤其是对于那些需要保护用户数据和隐私的网站。以下是必须启用HTTPS加密的网站类型:,,1. **电商平台**:包括相关支付系统和物流跟踪网站,保护用户的交易信息和个人信息。,,2. **金融机构**:银行系统、金融服务网站等涉及金融交易的高私密性网站。,,3. **政府机构**:政府、高校、科研机构及其相关网站,确保信息传输的安全和数据的完整性。,,4. **流量来源网站**:以搜索引擎为主要流量来源的网站,提高网站安全性,增强用户信任。,,5. **企业交流平台**:以邮箱为主的企业交流平台,保护商业通信和数据不被截获或篡改。,,HTTPS加密对于上述提到的网站类型至关重要,它不仅是提升网站安全性的必要措施,也是企业长远发展的重要布局。随着网络安全意识的提高,HTTPS将成为更多网站的标准配置。

    2024-07-17
    008
  • 如何安全地升级Master节点规格以提升集群性能?

    在Kubernetes集群中,升级Master节点规格通常涉及到硬件资源的提升,比如增加CPU、内存或者存储容量。这需要通过云服务提供商的管理控制台或使用相应的命令行工具来完成。升级过程中,应确保集群的高可用性,避免影响正在运行的服务。

    2024-08-18
    0015
  • 如何在MySQL中创建新数据库以支持特定的业务场景?

    在MySQL中,新建一个数据库可以使用CREATE DATABASE语句。如果要新建一个名为”business_scenario”的数据库,可以执行以下SQL命令:,,“sql,CREATE DATABASE business_scenario;,“

    2024-09-03
    0021

发表回复

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

广告合作

QQ:14239236

在线咨询: QQ交谈

邮件:asy@cxas.com

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

关注微信