首页/新闻资讯/正文详情

揭秘InnoDB 自增主键插入延迟与页分裂机制

发布时间:2026/9/27 21:44:25 来源:云帆数科 栏目:资讯中心
揭秘InnoDB 自增主键插入延迟与页分裂机制
主键自增明明是顺序插入为什么还会偶尔“卡”一下高并发往一张 InnoDB 表里INSERT主键是自增的。监控上经常能看到这样一条曲线平时 QPS 挺稳但隔一段时间延迟就会猛地翘一下QPS 跟着掉一截过几秒后自动恢复再过一会儿又翘一次。曲线呈规律的锯齿状。很多人把这个现象粗略地归结为「页分裂Page Split」认为是 B 树把数据页从中间劈开一半记录被搬走从而导致了慢。但这只说对了一半。页分裂确实发生了但在自增主键的场景下InnoDB 根本不会把页「从中间劈开」。它会将新行直接放到右边新开的页上而左边的老页依然是满的空间并没有被对半撕裂。真正让所有INSERT瞬间卡住的元凶是它们都挤在了同一片最右边的叶子页上。当这页快满需要分裂时分配新页、改前后链表、改父节点这段时间里所有后来的插入操作全都在这页的门口排队死等。分裂只是导火索对最右页的Latch闩锁排队踩踏才是你在监控上看到的那个“尖刺”。MySQL 8.0的InnoDB就是这么干的。我们扒开源码从底层来看看这个过程。1. 先看一页里有什么InnoDB默认一页是16KBinnodb_page_size。你可以把它想象成一张固定大小的带网格的纸数据绝不是随便往上堆的。纸的两头有两个固定的「哨兵」infimum比页内所有真实记录都小和supremum比所有真实记录都大。用户记录从页头往页尾长而用于二分查找的页目录Page Directory则从页尾往页头长中间剩下一截空地。叶子页还有指向「上一页/下一页」的指针FIL_PAGE_PREV、FIL_PAGE_NEXT串成了一个双向链表。范围扫描顺着链表走就行不用每次都回根节点。当插入一行数据时InnoDB会先在页里找到合适的位置再看中间的空地够不够。如果页内因为之前的删除留下了空洞虽然总字节数够但连不成一整块InnoDB会先在页内做一次整理reorganize把记录挤紧凑了再插。如果整理完还是放不下才会触发分裂。这条「先试试不行再分裂」的代码入口叫btr_cur_optimistic_insert()乐观插入放得下只改这一页写点Redo Log结束。日常绝大多数插入走的都是这条路。悲观分裂放不下返回失败。上层接着进入btr_page_split_and_insert()。要申请新页、搬运数据、修改父节点甚至导致B树长高。你在监控里看到的尖刺对应的就是少数几次悲观分裂耗时叠加当时所有并发插入都在这一页排队等待的综合结果。2. 聚簇页vs二级索引页痛点截然不同两棵树的页结构长得一样但叶子里装的“货”不一样导致它们的并发痛点完全不同。聚簇索引主键叶子节点存的是完整的整行数据附带InnoDB隐藏列trx_id和roll_ptr。二级索引叶子节点只存索引列主键列。因为装的货不同分裂时的代价差异巨大如果聚簇索引的一行非常宽比如2KB去掉页头信息一页根本放不了几条数据。没插几下就要分裂且一次搬走的字节量极大。行越宽一页装得越少监控上的尖刺就越密集。二级索引的记录通常很窄一页能塞很多条分裂没那么频繁。但是主键是顺序自增的二级索引列比如user_id往往是无序散列的。主键的痛点所有写入都集中在最右页排队。二级索引的痛点插入点满树乱跳页经常被从中间切开索引更容易产生碎片变胖。延伸提醒主键如果发生修改整行要在聚簇索引里搬家所有二级索引里的主键副本也得跟着改。所以主键千万别用业务上会变的列。3. 自增插入真的不是对半切到底在哪切这取决于btr_page_split_and_insert()怎么选切点。InnoDB每个数据页的头部有个字段叫PAGE_LAST_INSERT专门记录上一次数据插在了哪儿。如果本次插入的位置正好接在上一次的后面InnoDB就会判定“当前是顺序向右插入”从而走btr_page_get_split_rec_to_right()逻辑当插到页的最右端时**新记录会自己去当右边新页的第一条左边的老页原封不动。**如果右边还剩几条旧记录InnoDB会把它们搬到新页并在当前页保留一条。源码注释解释留这一条是为了让后续的顺序插入还能利用自适应哈希AHI在当前页对齐位置。自增主键就是典型的这种模式左页继续保持满载右页刚打开后面的INSERT继续往右页填填满再来一次。所以自增插入绝对不会让索引变成一堆半空的碎片页。相反如果主键是UUID或者是状态值这种跳来跳去的数据InnoDB看不出顺序就会走page_get_middle_rec()从中间切。这才是大家口中常说的「劈成两半」。大约一半记录被搬走产生更长的Redo Log分裂后两页都只有半满。如果持续这样随机插半满的页会越来越多不仅浪费Buffer Pool范围扫描也更吃亏。4. 一次悲观分裂底层到底在忙什么悲观分裂是一套组合拳都在btr_page_split_and_insert()里挨个执行定切点往左、往右还是从中间切。要新页调用btr_page_alloc()申请新页并尽量要求物理上靠近当前页减少随机IO。申请不到直接报错返回。挂链表调用btr_attach_half_pages()把新页挂进B树修改前后页的指针并在父节点加上指向新页的记录如果父页也满了分裂会向上传导极端情况下根节点分裂树高加一。释放树锁如果新行放得下InnoDB会尽早释放整棵索引树的Latch。如果树锁抓太久别的插入连其他无关的页都进不去。搬数据最后才是把该搬的记录搬过去把新行写进去。一个小细节预留的1/16空间在连续向一侧插入且页未压缩时如果页内剩余空间小于「这一行的宽度一页的1/16约1KB」乐观插入会主动放弃提前去分裂。 注释里的理由很实在如果页被连续插入彻底塞死以后要是发生UPDATE把变长字段改大页会碎得很厉害。所以最右页「看着还有一点空就开始分裂」多半是触发了这个1KB的保护线而不是空间算错了。5. 尖刺在监控上到底长什么样假设有一张普通的订单表CREATE TABLE orders ( id BIGINT NOT NULL AUTO_INCREMENT, user_id BIGINT NOT NULL, payload VARCHAR(512), PRIMARY KEY (id), KEY idx_user (user_id) ) ENGINEInnoDB;业务侧有几十个连接同时INSERT。因为id越来越大所有线程算出来的插入目标全落在最右边那片叶子上。修改这页必须拿到排他X性质的Page Latch。同一时刻只能有一个插入在改它其他人全在门口等。正常情况下如果空地够乐观插入极快排队无感。 一旦空地不够触发悲观分裂申请新页、改链表、改父节点……操作耗时拉长门口的队伍瞬间变长监控上延迟直接翘起来QPS掉下去。分裂一结束新的最右页诞生继续飞速接客延迟瞬间掉回去。等这页再次被填满再来一轮。所以你看到的曲线是锯齿而不是越跑越慢。如果payload字段很大一页装不了几行这个锯齿就会非常密集。避坑指南别把页Latch和表级的AUTO-INC锁混为一谈。在MySQL 8.0中innodb_autoinc_lock_mode默认是2普通INSERT获取自增值几乎没有表级锁等待。如果你在锁监控里没看到AUTO-INC锁只有大量等待同一个index page的semaphore那就是最右页Latch被打满了。6. 两种常见的对比场景删数据也会卡但卡的不在同一处当你批量DELETE历史数据时页被掏空btr_compress()会尝试把空页和相邻页合并。这同样需要拿Page Latch、改链表、改父节点。 白天高并发自增写入卡在最右页夜里跑定时任务删老数据卡在被删的旧数据段。两件事经常叠在一张表上遇到这种情况先排查慢在哪别一上来就喊「索引坏了重建吧」。换成UUID主键会怎样UUID会让插入点散落在满树的各个节点单页上的并发争抢立刻缓解最右页的锯齿尖刺会大幅减轻。 但代价转移了页经常从中间切开产生大量半满页同样的数据量占用更多的页导致Buffer Pool命中率下降磁盘随机IO和逻辑读大幅上升。自增主键是用「所有写挤在一页」换取「树更紧凑、范围扫描更顺」。没有绝对的好坏取决于你的并发量和查询模式是否吃索引的紧凑度。7. 线上碰到了该怎么看和处理排查路径确认尖刺是否伴随大量INSERT且当时没有大规模DELETE排除页合并的干扰。使用SHOW ENGINE INNODB STATUS查看semaphore段。如果有大量线程等同一个index page且行锁和MDL锁都很干净基本就是最右页Latch争用。检查单行数据的宽度行越宽分裂越频繁以及是否有另一个非常热的二级索引。处理手段保持自增瘦身表结构主键继续自增。把大JSON、大文本TEXT/BLOB拆分到旁路表让主表叶子节点变窄。一页能放的行数翻倍分裂频率和搬运代价就会减半。保持参数确认innodb_autoinc_lock_mode2别乱改回1或0避免引入不必要的表级自增锁。打散热点如果写入并发实在太高单页Latch成了绝对瓶颈可以考虑按租户、时间或者Hash分表。让「1个最右页」变成「N个表的最右页」把并发摊开。别白费力气调innodb_fill_factor消除不了这个锯齿。该参数主要影响重建索引DDL时的填充率无法阻止运行时为了预留Update空间而触发的1/16分裂机制。总结最右页满了会分裂新行去右边左页保持紧凑。所有并发写入都在同一页抢Latch分裂那一下排队队伍变长监控上就会出现一下一下的尖刺。理清了这个底层逻辑你就能精准地决定是该“缩窄行宽”还是该“打散热点”而不是盲目地去重建索引。

相关推荐

基于Claude Skill技术实现文章审查:SKILL.md配置与验证指南
基于Claude Skill技术实现文章审查:SKILL.md配置与验证指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 21:44:19

Qiskit 随机电路生成指南:random_circuit、random_circuit_from_graph 与 random_clifford_circuit 全面解析
Qiskit 随机电路生成指南:random_circuit、random_circuit_from_graph 与 random_clifford_circuit 全面解析

科学计算 【免费下载链接】qiskit Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives. 项目地址: https://gitcode.com/gh_mirrors/qi/qiskit 点击查看 免费下载 本文围绕 … · 2026/9/27 21:44:19

From Monolingual to Bilingual: Investigating Language Conditioning in Large Language Models for P...
From Monolingual to Bilingual: Investigating Language Conditioning in Large Language Models for P...

文章主要内容和创新点 主要内容 本文聚焦于利用大型语言模型(LLMs)解决开源技术文档的语言障碍问题,核心研究包括三部分: 开源社区翻译活动分析:通过对不同规模(小型、中型、大型)开源仓库的拉取请求(PRs)和议题(Issues)分析,发现翻译活动集中在大型仓库,且多为… · 2026/9/27 21:44:19

CTF为什么总是做不出来?Web、密码学、逆向三大题型新手解题思路总结​
CTF为什么总是做不出来?Web、密码学、逆向三大题型新手解题思路总结​

引言 CTF(Capture The Flag,夺旗挑战)是网络安全领域最经典的竞赛形式之一,参赛者需要在短时间内从零开始发现并利用安全漏洞,获得目标服务器上的 Flag(通常是一个隐藏的字符串)。这项赛事自 19… · 2026/9/27 22:15:48

Spring AI Alibaba 企业级 AI 应用开发框架:用 TaoToken 统一 Key 打通百炼平台多智能体配置
Spring AI Alibaba 企业级 AI 应用开发框架:用 TaoToken 统一 Key 打通百炼平台多智能体配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:15:48

Cursor Pro 配 TaoToken:settings.json 骨架与报错排查
Cursor Pro 配 TaoToken:settings.json 骨架与报错排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:15:48

使用 Ollama + Qwen3-14B 配置 opencode(RTX 3060 12GB 显存):TaoToken 统一 Key 接入与本地模型切换
使用 Ollama + Qwen3-14B 配置 opencode(RTX 3060 12GB 显存):TaoToken 统一 Key 接入与本地模型切换

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 22:15:48

有区域名和主机怎么做网站2026最新实操避坑指南
有区域名和主机怎么做网站2026最新实操避坑指南

有区域名和主机怎么做网站2026最新实操避坑指南 网站做好了没人访问,这是很多刚拿到域名和主机的站长最头疼的事。别急,2026年的搜索环境变了,光有站不够,得让搜索引擎“看懂”你。今天咱不整虚的,直接拆解从域名解析到SEO落地的完整链路,帮… · 2026/9/27 22:15:48

数据库中的索引
数据库中的索引

一、索引到底解决什么问题?先看没有索引时,数据库怎么查数据。假设有一张 users 表,存了 100 万条用户记录。执行:SELECT * FROM users WHERE username zhangsan;数据库只能从第 1 行开始,逐行扫描,直到找… · 2026/9/27 22:15:42

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码