InnoDB表聚集索引层高什么时候发生变化(1)

简介: InnoDB表聚集索引层高什么时候发生变化

导读

本文略长,主要解决以下几个疑问


1、聚集索引里都存储了什么宝贝2、什么时候索引层高会发生变化3、预留的1/16空闲空间做什么用的4、记录被删除后的空间能回收重复利用吗

1、背景信息

1.1 关于innodb_fill_factor

有个选项 innodb_fill_factor 用于定义InnoDB page的填充率,默认值是100,但其实最高只能填充约15KB的数据,因为InnoDB会预留1/16的空闲空间。在InnoDB文档中,有这么一段话

An innodb_fill_factor setting of 100 leaves 1/16 of the space in clustered index pages free for future index growth.

另外,文档中还有这样一段话

When new records are inserted into an InnoDB clustered index, InnoDB tries to leave 1/16 of the page free for future insertions and updates of the index records. If index records are inserted in a sequential order (ascending or descending), the resulting index pages are about 15/16 full. If records are inserted in a random order, the pages are from 1/2 to 15/16 full.

上面这两段话,综合起来理解,就是

  1. 即便 innodb_fill_factor=100,也会预留1/16的空闲空间,用于现存记录长度扩展用
  2. 在最佳的顺序写入数据模式下,page填充率有可能可以达到15/16
  3. 在随机写入新数据模式下,page填充率约为 1/2 ~ 15/16
  4. 预留1/16这个规则,只针对聚集索引的叶子节点有效。对于聚集索引的非叶子节点以及辅助索引(叶子及非叶子)节点都没有这个规则
  5. 不过 innodb_fill_factor 选项对叶子节点及非叶子节点都有效,但对存储text/blob溢出列的page无效

1.2 关于innodb_ruby项目

innodb_ruby 项目是由Jeremy Cole 和 Davi Arnaut 两位大神开发的项目,可用于解析InnoDB数据结构,用ruby开发而成。他们还维护了另一个众所周知的项目叫 InnoDB Diagrams,相信稍微资深一点的MySQL DBA都应该知道这个项目。

1.3 关于innblock工具

由八怪开发,用于扫描和分析InnoDB page,详见 innblock | InnoDB page观察利器

1.4 阅读本文背景信息

需要假设您对InnoDB的数据结构已经有了一定了解,包括B+树、聚集索引、辅助索引,以及innodb page的一些简单结构。

如果不太肯定,请先阅读这些文档内容

  • Clustered and Secondary Indexes
  • The Physical Structure of an InnoDB Index
  • InnoDB Row Formats
  • InnoDB Record Structure
  • InnoDB Page Structure

2、测试验证:一层高的InnoDB表聚集索引,最多能存多少条数据

从上面我们知道,一个page最大约能存储15/16容量,扣掉用于存储page header、trailer信息,以及index header、File Segment Header、Infimum&Supremum(两条虚拟记录)等必要的固定消耗之后,实际大约只有15212字节可用于存储用户数据。

这样一来,我们就可以简单测算出一个page大约能存储多少条记录了。

本次用到的测试表,只有一个INT列,同时作为主键建议横版观看,可左右滑动。或者复制链接到PC端打开观看,效果更佳。下同

# MySQL的版本是Percona Server 5.7.22-22,我自己下载源码编译的
[root@yejr.me#] mysql -Smysql.sock innodb
...
Server version: 5.7.22-22-log Source distribution
...
[root@yejr.me]> \s
...
Server version:     5.7.22-22-log Source distribution

# 创建测试表
[root@yejr.me]> CREATE TABLE `t1` (
  `i` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`i`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

另外,我们知道每条记录都要几个额外存储的数据

  • DB_TRX_ID,6字节
  • DB_ROLL_PTR,7字节
  • Record Header,至少5字节(用上面这个测试表,只需要5字节,不同数据类型需要的header长度也不同,详见 浅析InnoDB Record Header及page overflow
  • 因此,一条数据需要消耗 4(INT列) + 6 + 7 + 5 = 22字节
  • 此外,大约每4条记录就需要一个directory slot,每个slot需要2字节
  • 综上,假设可以存储N条记录,则 N*22 + N/4*2 = 15212,可求得N约等于676

接下来我们验证一下,往该表中持续插入 676 条数据

[root@yejr.me]> insert into t1 select 0;

...
# 逐次反复执行676次

然后,我们利用 innodb_ruby 工具查看其数据结构

2.1 查看聚集索引page结构

此时t1表的聚集索引树只有一层高,一个page即pageno=3

[root@yejr]# innodb_space -s ibdata1 -T innodb/t1 space-indexes

id name root fseg fseg_id used allocated fill_factor
128 PRIMARY 3 internal 1 1 1 100.00%
128 PRIMARY 3 leaf 2 0 0 0.00%

再用innblock工具扫描佐证一下

[root@yejr]# innblock innodb/t1.ibd scan 16
...
level0 total block is (1)
block_no: 3,level: 0|*|

2.2 查看其directory slot

可以看到170个slot,其中Infimum记录的owned=1,Supremum记录的owned=5

[root@yejr]# innodb_space -s ibdata1 -T innodb/t1 \
-p 3 page-directory-summary|grep -c -v slot

170

2.3 查看整个page的全览图

前面是一堆头信息

[root@yejr]# innodb_space -s ibdata1 -T innodb/t1 -p 3 page-illustrate

Offset ╭────────────────────────────────────────────────────────────────╮
0 │█████████████████████████████████████▋██████████████████████████│
64 │█████████▋███████████████████▋████████████▋████████████▋████▋███│
# 大概从这里开始是第一条记录
128 │█████████████▋████▋████████████████▋████▋████████████████▋████▋█│
192 │███████████████▋████▋████████████████▋████▋████████████████▋████│
...
# 中间是用户数据
...
# 这里是预留的1/16空闲空间
15872 │ │
15936 │ │
# 这里是page directory slot,逆序存储
# trailer占用8字节,此后每个slot占用2字节
# 共170个slot
16000 │ █▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋│
...
16320 │█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋█▋███████▋│
╰────────────────────────────────────────────────────────────────╯

# 最后是统计汇总信息
Legend (█ = 1 byte):
Region Type Bytes Ratio
█ FIL Header 38 0.23%
█ Index Header 36 0.22%
█ File Segment Header 20 0.12%
█ Infimum 13 0.08%
█ Supremum 13 0.08%
█ Record Header 3380 20.63%
█ Record Data 11492 70.14%
█ Page Directory 340 2.08%
█ FIL Trailer 8 0.05%
░ Garbage 0 0.00%
Free 1044 6.37%

可以得到几点信息

  • Record Data共占用11492字节,共676条记录,每条记录17字节(4+6+7)
  • Page Directory共340字节,170个slot,每个slot占用2字节
  • 两条虚拟记录,均占用13字节(含5字节的record header)
  • Record Header共3380字节,共676条记录,每条记录需要5字节头信息(再次提醒,表里字段类型各异,Record Header也会随之不同,仅在本例中只需要5字节。详见 浅析InnoDB Record Header及page overflow
  • 提醒:本次测试是顺序写入,如果是随机写入或批量写入,可能就没办法把15/16的page空间填充的满满当当了


            </div>
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
Web App开发
如何实现一个项目配置多个商户信息付款给对应商户
说明:本帖主要说明如何实现给一个平台配置多个商户的号实现多个商户收款。主要用于没有门店和第三方授权方式 支付宝最终是根据请求过来的appid来判断哪一个商户收款(也就是请求是谁的appid就收款到谁的账号下)    方案一:      1.
1587 12
|
物联网 API 开发工具
魔搭文生图MCP:一个MCP调用魔搭模型库的12800+个文生图模型!
魔搭社区的AIGC专区很早就支持了Flux的LoRA训练,截止到目前为止,基于Flux架构的衍生LoRA已经有1万多个。这些模型除了在AIGC专区的在线生图可以直接推理之外,魔搭也使用云资源部署了API-Inference服务,提供了API接口供开发者免费调用。
612 0
|
编解码 前端开发 API
使用 DPR 进行响应式设计
【10月更文挑战第24天】我们可以利用 DPR 来实现更精细、更自适应的响应式设计,为用户提供更好的视觉体验,无论他们使用的是什么设备。
|
10月前
|
数据采集 监控 大数据
大数据项目管理:从规划到执行的全景指南
大数据项目管理:从规划到执行的全景指南
184 4
|
人工智能 安全 大数据
元宇宙游戏:沉浸式体验的新纪元
在科技飞速发展的今天,元宇宙游戏作为融合了虚拟现实(VR)、增强现实(AR)、人工智能(AI)与区块链等前沿技术的数字新世界,正引领我们进入一个前所未有的沉浸式体验时代。本文将深入探讨元宇宙游戏的特点、技术基础及其如何引领沉浸式体验的新潮流。
|
Cloud Native API 云计算
云原生架构的深度探索与实践####
本文深入探讨了云原生架构的核心概念、技术特点及其在现代软件开发中的应用实践。通过分析云原生架构如何促进企业数字化转型,提升业务敏捷性与可扩展性,本文旨在为读者提供一个全面而深入的理解框架。我们将从云原生的定义出发,逐步深入到其关键技术组件、最佳实践案例及面临的挑战与解决方案,为开发者和企业决策者提供宝贵的参考与启示。 ####
|
存储 人工智能
西门子S7-200 SMART Modbus RTU通信,如何编写从站程序
上篇文章中我们通过一个例子学习了西门子S7-200 SMART中断程序的编写,本篇我们开始学习S7-200 SMART的Modbus RTU通信。通过集成RS485端口或可选通信板SM CM01的RS485/RS232端口,S7-200 SMART可以作为Modbus RTU主站或者从站同多个设备进行通信。
西门子S7-200 SMART Modbus RTU通信,如何编写从站程序
|
消息中间件 存储 运维
让数据流动起来,RocketMQ Connect 技术架构解析
本文介绍了 RocketMQ Connect 的概念,然后讲解了 RocketMQ Connect 的实现原理,对服务发现,配置同步,位点同步,负载均衡都有了初步的介绍,接着以 MySqlSourceConnector 为例讲解了如何自己实现一个 Connector,最后对 Connect API 和生态做了一些介绍,提供了一些 RocketMQ Connect 相关的上手教程。
让数据流动起来,RocketMQ Connect 技术架构解析
|
开发框架 Dart 前端开发
初探Flutter在IoT场景下生态和趋势
IoT 领域,一个避不开的词就是碎片化。在硬件方面,厂商、架构、芯片、传感器等等方面的差异,形成了硬件体系的多样性。
初探Flutter在IoT场景下生态和趋势