尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
MySQL 二级索引的非叶子节点存了什么:索引值、主键值和子页号指针
MySQL 二级索引的非叶子节点存了什么索引值、主键值和子页号指针二级索引的查找要先用索引键定位再拿主键回表。这篇从一条二级索引查询出发拆开非叶子节点的记录结构说明索引值、主键值和子页号各自负责什么并给出可复核的官方文档和验证入口。一、使用场景二级索引列的值重复度很高时这个结构问题才会真正暴露。比如订单表在 status 上建索引几十万行都是 paid仅靠 status 无法把记录排成唯一顺序也无法决定查询应该往哪个子页走。这时主键必须参与比较二级索引的键实际变成索引列加主键的组合。主键变长也有同样的影响。InnoDB 会把主键追加到每个二级索引主键越长二级索引占用的空间越大非叶子页能容纳的分隔键越少树的层数也更容易升高。手册 17.6.2.1 对此有一句直接说明主键较长时二级索引会占用更多空间因此短主键更有优势。二、核心概念InnoDB 的表数据按 B 树组织。聚簇索引的叶子页存放完整行二级索引的叶子页存放索引列和主键列位于两者之上的非叶子页只负责导航。页头的 PAGE_LEVEL 记录当前页在树中的层级0 表示叶子页。手册 17.11.2 还说明每个索引会分配两个 segment一个给非叶子节点一个给叶子节点。官方手册对二级索引记录的组成写得很明确In InnoDB, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index. InnoDB uses this primary key value to search for the row in the clustered index.这句话覆盖的是每条二级索引记录。再结合 10.3.10 的索引延伸规则InnoDB 会自动把主键列追加到每个二级索引声明为 k_d(d) 的索引在内部按 (d, i1, i2) 处理。二级索引的完整键是索引列在前、主键列在后键长和排序位置都按这个组合计算。非叶子页的每条记录由三部分组成索引值分隔键的头部决定第一轮比较。主键值索引值相同时继续比较让组合键在树中有唯一位置。子页号下一层页面的编号沿着它继续下降。用两层树表示这个结构根页 / 中间页PAGE_LEVEL 0 (d2000-01-01, i11, i22) - 子页号 12 (d2000-01-02, i11, i21) - 子页号 27 │ ▼ 叶子页PAGE_LEVEL 0 (d2000-01-01, i11, i22) - 聚簇索引中的 (1, 2) 行叶子记录与非叶子记录的差别在尾部叶子记录带完整键并用主键指向聚簇索引中的行非叶子记录在键后面接子页号。MySQL Server 源码文档对 btr_node_ptr_get_child_page_no 的说明是“Gets the child node file address in a node pointer”即 node pointer 中保存的是子页地址btr_page_get_level 的注释则明确“leaf level 0”可以据此区分层级。需要区分的是子页号指向 B 树中的页面并不指向数据行也不等同于聚簇索引的页号。二级索引只保存主键值回表时再由主键到聚簇索引里定位整行。三、最小代码用一张复合主键加单列二级索引的表就能看到这个结构createtablet1(i1intnotnulldefault0,i2intnotnulldefault0,ddatedefaultnull,primarykey(i1,i2),keyk_d(d))engineinnodb;insertintot1values(1,1,2000-01-01),(1,2,2000-01-01),(2,1,2000-01-01),(2,2,2000-01-01),(3,1,2000-01-01),(3,2,2000-01-01),(4,1,2000-01-01),(4,2,2000-01-01);主键是 (i1, i2)二级索引只声明了 d。八条记录的 d 完全相同仅看 d 无法排序InnoDB 把主键追加到 k_d 之后索引键变成 (d, i1, i2)记录才能按 (d, 1, 1)、(d, 1, 2)、(d, 2, 1) 这样的顺序排开。非叶子页保存的分隔键也必须是这个组合否则上层无法判断一条新记录该落到哪个子页。四、执行流程以select count(*) from t1 where i1 3 and d 2000-01-01为例查找沿下面这条路径推进优化器选择 k_d按扩展后的 (d, i1, i2) 把 d 和 i1 当作键的左侧前缀。从根页开始用目标键与每条分隔键比较先比 d相同再比 i1i2 没有出现在条件里用来在相同前缀内确定扫描起点。找到合适的子页号后进入下一层中间页重复同样的比较直到到达叶子页。叶子页内做二分命中记录后取出主键 (i1, i2)。查询列被索引覆盖时直接返回需要其他列时拿主键回聚簇索引取整行。插入导致页分裂时新页的首条键会作为 node pointer 写入上层上层也满时继续向上分裂根页分裂后树高增加一层。这套流程里非叶子页承担的职责很单一提供分隔键和下一跳页号。它不保存行数据也不保存聚簇索引的页号所以页分裂时只需要调整分隔键和子页号不必移动行。五、常见坑只记住“二级索引存索引列”漏掉主键参与排序。遇到重复值多的索引就无法解释定位过程也容易把索引延伸理解成优化器的可选行为。把子页号当成行地址或聚簇索引页号。二级索引叶子记录里只有主键值回表是另外一跳页号只服务于 B 树内部的下降。用 SHOW INDEX 判断索引的真实键。SHOW INDEX 只显示声明的 d追加的主键列不会出现key_len 和查询计划才能反映扩展后的前缀。低估长主键的代价。主键列会出现在每个二级索引的每一层字符型主键尤其明显索引体积和树高都会随之增加。把唯一二级索引当成例外。唯一索引的分隔键本身已经唯一路由时不需要再靠主键补足叶子记录仍然带主键用于回表索引延伸带来的空间开销不变。六、验证方式本文没有在本机 MySQL 实例上执行这些语句下面给的是可复现路径预期值来自手册 10.3.10 的示例输出。建表插数据后先清空表缓存和状态计数器flushtables;flushstatus;再看执行计划explainselectcount(*)fromt1wherei13andd2000-01-01;手册示例中优化器不考虑索引延伸时 key_len 是 4、ref 是 const、rows 是 5考虑延伸后 key_len 变成 8、ref 变成 const,const、rows 变成 1。key_len 从 4 增加到 8说明查询用上了 d 后面的 i1二级索引记录确实带主键列。当前数据里 i13 有两行rows 会与手册不同key_len 和 ref 这两个值仍然能说明问题。扫描行数可以进一步确认showstatuslikehandler_read%;手册示例中 Handler_read_next 从 5 降到 1。在当前数据下这个值应当接近匹配的记录数而不是按 d 值全扫。索引声明本身看不到扩展部分showindexfromt1;结果只列出 PRIMARY(i1, i2) 和 k_d(d)追加的主键列不会显示出来。这里正是“声明键”和“物理键”需要分开看的地方。需要直接观察页内记录时可以用 innodb_ruby 提供的 innodb_space 按页转储innodb_space-ft1.ibd-p3page-dump按该工具的说明非叶子页会列出 node pointer 的键值和子页号叶子页会列出完整记录。这个工具不属于 MySQL 自带命令适合本地观察页结构生产环境不要依赖它。七、总结二级索引的非叶子节点承担路由不承担数据。它保存的键是索引列加主键的组合尾部接子页号叶子记录才带完整键并用主键回表。判断一条二级索引查询的成本时先看键的完整组成再看查询列是否被索引覆盖就能判断会不会多一次回表。参考资料MySQL 8.4 Reference Manual 17.6.2.1 Clustered and Secondary IndexesMySQL 8.4 Reference Manual 10.3.10 Use of Index ExtensionsMySQL 8.4 Reference Manual 17.10 InnoDB Row FormatsMySQL 8.4 Reference Manual 17.11.2 File Space ManagementMySQL Internals: InnoDB Page StructureMySQL Internals: Page HeaderMySQL Server Source Documentation: btr0btr.h
RELATED

相关推荐

把问数平台接进园区系统,我按这五步落地

把问数平台接进园区系统,我按这五步落地

前面几篇聊过问数平台的架构、语义层,还有结果为什么能核对。这篇换个角度,讲落地。我们这边有两套东西。一套是园区数字化管理平台,把房源、租客、合同、账单这些日常数据收口管理。另一套是数智安全问数平台,让业务方用大白话开…

📅 2026/10/27 10:29:07
别再照着榜单签约了!产业研究与智库机构Top5盘点,五类画像帮你对号入座

别再照着榜单签约了!产业研究与智库机构Top5盘点,五类画像帮你对号入座

上周隔壁部门的老板甩来一个活儿:“帮我找家机构,把咱们行业明年的趋势摸清楚,预算下周要报。”打开搜索引擎,研究院、咨询公司、数据服务商刷出几十个榜单,名次各说各话,报价从几千到几十万都有&#xff0…

📅 2026/10/27 10:29:07
迈普 NSS3330 端口安全配置:MAX 规则、STICKY 固化与 MAC 学习限制的区别

迈普 NSS3330 端口安全配置:MAX 规则、STICKY 固化与 MAC 学习限制的区别

问题背景 接入层的常见风险是单个接入口被私接交换机或路由器占用,短时间内学习到大量 MAC 地址,导致 MAC 表项耗尽,正常终端流量被迫泛洪。限制单端口可学习的 MAC 数量,是最直接的缓解手段。 NSS3330 对此提供两套机制&#xff…

📅 2026/10/27 10:29:07
MORE NEWS

更多资讯

📰

OpenCV多角度多尺度模板匹配技术详解

1. 多角度多尺度模板匹配技术解析 在工业视觉检测、医学影像分析等领域,我们经常需要从复杂背景中定位特定目标物体。传统模板匹配方法存在两大痛点:一是目标可能出现任意旋转角度,二是目标尺寸可能发生缩放变化。这正是多角度多尺度模板匹配…

📰

Windows本地Flink CDC实现MySQL实时同步实战指南

1. 为什么要在 Windows 上折腾 Flink 与 MySQL 同步 很多做数据处理的同行一听到“Flink 跑在 Windows 上”,第一反应是皱眉头——生产环境清一色 Linux,本地搞 Windows 图什么?我最初也是这个态度,直到实际带过几个项目之后才发现…

📰

零基础转型AI大模型:四阶段实战路线图

1. 项目概述:零基础程序员如何系统转型AI大模型领域 去年我帮团队里三位Java后端开发成功转型成大模型算法工程师,完整走通了从编程基础到工业级落地的全流程。这个四阶段学习路线图就是根据实战经验提炼的黄金路径,特别适合有编程基础但缺乏…

📰

基于MySQL的图书管理系统实战:从建表到借书事务与并发控制

简介:这份资源是面向高校学生与数据库初学者的MySQL图书管理系统课程设计完整包,可作为数据库期末大作业的参考实现。系统围绕图书表、读者表、管理员表、借阅表与逾期处罚表五类核心数据表展开,实现了借还书流程、模糊查询以及按权限区分用户…

📰

Camunda工作流邮件通知实战:Mail Task与JavaDelegate委托详解

工作流引擎跑到生产环境之后,业务方提的需求里十有八九会冒出一条:某个审批节点要通过邮件通知到人。Camunda 本身把「发邮件」这件事做成了引擎内置的一等公民,但真到落地的时候,坑往往不在「能不能发出去」,而在「模…

📰

Apache SeaTunnel二次开发实战与生态解析

1. 从Meetup看Apache SeaTunnel的生态活力 上周参加完本地技术社区的Meetup活动,对Apache SeaTunnel这个开源数据集成工具又有了新的认识。作为一款源自国内的开源项目,SeaTunnel在近两年快速崛起,已经成为大数据领域不可忽视的力量。活动现场…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬