关于MYSQL INNODB index page header学习和实验总结

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 关于INNODB  index header 所用到的工具是自己写的mysqlblock和bcview, 我放到了百度云盘 http://pan.baidu.com/s/1num76RJ 供大家下载和使用 普通表空间(及设置了innodb_file_per_table每个表都对应一个idb文件)从第4个块开始通常是innodb的数据页。
关于INNODB  index header


所用到的工具是自己写的mysqlblock和bcview,
我放到了百度云盘
http://pan.baidu.com/s/1num76RJ
供大家下载和使用


普通表空间(及设置了innodb_file_per_table每个表都对应一个idb文件)从第4个块开始通常是innodb的数据页。
前38字节为FILE HEADER
从38字节到74字节为INDEX HEADER,如下:


number of directory slot            2bytes 槽的个数,
heap top position                   2bytes 块的最高数据记录的偏移地址
number of heap records/format flag  2bytes 行的记录数量但是第15位为行模式的标示如果15位为1,就是COMPACT模式
first garbage record offset         2bytes 第一行删除记录的偏移量
garbage space                       2bytes 删除的空间大小单位bytes
last insert position                2bytes 最后一个插入的位置偏移量
page direction                      2bytes 行的插入方向,取值为左,右或者无顺序 0x02 右 0x01 左  0x05 无序
number of inerts in page direction  2bytes 同一方向插入数据的行数,如果方向改变则重置
number of record                    2bytes 总的行数
maximum transaction id              8bytes 最大事物的ID
page level                          2bytes 页的级别,页节点为0,然后网上加1,如果3层,根节点为 2,分支节点为1,页节点为0
index ID                            8bytes 索引的ID这个在INNODB_SYS_INDEXES也是有的


接下来分析我设置了innodb_file_per_table
create table km1(id int ,name varchar(20));
insert into km1 values(1,'gaopeng');
insert into km1 values(2,'gaopeng');
insert into km1 values(3,'gaopeng'); 
insert into km1 values(4,'gaopeng'); 


分析文件:
[root@hadoop1 test]# mysqlblock km1.ibd -d|more
***************************************************
USEAGE: mysqlblock datafile -t/-d                  
This small tool used in study and test database,not
uesd on online database!                           
This tool is used to find how many blocks and types
in specified datafile,Exp:how many undo block in d 
ata file!                                          
QQ:2238980                                         
***************************************************
-t Only Total blocks types in ibdata!              
-d Blocks types detail  in ibdata!                 
***************************************************
FILE SIZE IS : 98304
current read blocks is : 0 --This Block is file space header blocks!
current read blocks is : 1 --This Block is insert buffer bitmap  blocks!
current read blocks is : 2 --This Block is inode blocks!
current read blocks is : 3 --This Block is data blocks( index pages)!
current read blocks is : 4 --This Block is new allocate blocks!
current read blocks is : 5 --This Block is new allocate blocks!
Total Block Status    :
Total  block                   :     6,Total size is: 0.093750 MB
Total undo block               :     0,Total size is: 0.000000 MB
Total inode block              :     1,Total size is: 0.015625 MB
Total insert buffer free blocks:     0,Total size is: 0.000000 MB
Total data(index pages) block  :     1,Total size is: 0.015625 MB
Total new allocate blocks      :     2,Total size is: 0.031250 MB
Total insert buf bitmap blocks :     1,Total size is: 0.015625 MB
Total system blocks            :     0,Total size is: 0.000000 MB
Total transaction system blocks:     0,Total size is: 0.000000 MB
Total file space header blocks :     1,Total size is: 0.015625 MB
Total extrenl disc blocks      :     0,Total size is: 0.000000 MB
Total LOB blocks               :     0,Total size is: 0.000000 MB
Total Unkown blocks            :     0,Total size is: 0.000000 MB


我这里数据很少,值有3条,所以一共就只有6个块,块3就是数据块(0 开始)使用

1、number of directory slot
bcview km1.ibd 16 38 2|more
current block:00000003--Offset:00038--cnt bytes:02--data is:0002
这里有一个槽的概念,他实际上是用于更快的定位数据,以后的文章会更加细节的研究学习

2、heap top position 
bcview km1.ibd 16 40 2|more
current block:00000003--Offset:00040--cnt bytes:02--data is:010c
表明记录的最高为出现在偏移量10c,及十六进制的268

3、number of heap records/format flag 

bcview km1.ibd 16 42 2|more
current block:00000003--Offset:00042--cnt bytes:02--data is:8006
这里8006十六进制,就说明是compact模式的行记录,如果使用Redundant我们看看
 create table km3 (id int,name varchar(20)) ROW_FORMAT = Redundant;
current block:00000003--Offset:00042--cnt bytes:02--data is:0002
可以看到这里第15为为0,说明是Redundant格式
而我们的行记录是6,明明只是插入了4条记录为什么是6呢,其实MYSQL的每个块里面有
2个虚拟列infimum 和supremum,他们都在固定的位置,而 infimum指向了第一条记录的
offset,而最后一条记录的offset表示为supremum的offset,这样形成了行记录的一个
单项链表。
4、first garbage record offset 
bcview km1.ibd 16 44 2|more
current block:00000003--Offset:00044--cnt bytes:02--data is:0000
为0,如果说明没有删除的记录,如果此时我们来delete 2条记录
delete from km1 where id in (1,3);
(由于bcview为基于文件的工具,修改的数据脏数据卸载buffer中,所以我重启了一次数据才能看到)
再次查看
current block:00000003--Offset:00044--cnt bytes:02--data is:00c9
看到这里为c9及offset 201

5、garbage space
bcview km1.ibd 16 46 2|more
current block:00000003--Offset:00046--cnt bytes:02--data is:004a
这里删除的字节为4a及74个字节,为什么我删除了2行数据却有这么多字节呢?
其实每行的数据除了数据本身还有很还有24个字节左右的开销,并且我们这里
没有主键的表MYSQL INNODB会自动生成一个6字节的48位的ROWID,那么加上就是
大约30个字节的开销,如果有建表的时候加上了主键ROWID 6字节开销就没了,同样
实验一下:
create table km4 (id int primary key,name varchar(1000));
insert into km4 values(1,'gaopeng');
insert into km4 values(2,'gaopeng');
insert into km4 values(3,'gaopeng'); 
insert into km4 values(4,'gaopeng'); 
delete from km4 where id in (1,3);
再次查看km4
 bcview km4.ibd 16 46 2|more
current block:00000003--Offset:00046--cnt bytes:02--data is:003
这里3e是十进制62,74-62=12 刚好6字节证明了我的说法。
还要注意一点:如果建表的时候没有加入主键,插入数据后加入,这每行6字节的开销也是有的,所以建表的时候尽量要加主键。
如果没有删除的行或者所有删除的空间从用了这个值减少为0.

6、last insert position 
bcview km1.ibd 16 48 2|more
current block:00000003--Offset:00048--cnt bytes:02--data is:0000

这个取值在没有删除重用空间的时候都0,但是随后的测试中这个值代表的
是最后一次插入的偏移量。如果使用的是删除的空间,那么这个值会出现
指向小于当前偏移量的情况,因为删除的数据的空间在当前行的物理偏移量
以前

7、page direction

bcview km1.ibd 16 50 2|more
current block:00000003--Offset:00050--cnt bytes:02--data is:0002

这里代表的插入的顺序为0x02 右

8、number of inerts in page direction
bcview km1.ibd 16 52 2|more
current block:00000003--Offset:00052--cnt bytes:02--data is:0003

这里代表以0x02 这个顺序插入数据的行数为4-1,因为我插入了4行它为3

9、number of record  
bcview km1.ibd 16 54 2|more
current block:00000003--Offset:00054--cnt bytes:02--data is:0002

可以看到这里的行数实际为2了因为我删除了2行,而
number of heap records/format flag
的记录还是8006,可以看到记录还是6,除掉infimum 和supremum还有4行。
那么我们可以得到一个结论
number of heap records 是本block中 delete的行数+未delete的行数+infimum 和supremum=6
而number of record     是本block中 未delete的行数

我们可以做下实验:
现在表中有2行,我们增加一行数据看看变化
mysql> insert into km1 values(5,'gaopeng');
number of record 
current block:00000003--Offset:00054--cnt bytes:02--data is:0003
number of heap records/format flag
current block:00000003--Offset:00042--cnt bytes:02--data is:8006
可以看到我们的空闲的空间重用了,因为number of heap records还是6,而number of record变成了3

那么还可以看看page direction和number of inerts in page direction
按照理论既然是重用了空间,那会插入的顺序是相反的,那么这两个值会有所变化
不出所料
page direction
current block:00000003--Offset:00050--cnt bytes:02--data is:0005
值为5
number of inerts in page direction
current block:00000003--Offset:00052--cnt bytes:02--data is:0000
变为了0,因为顺序改变了0X02改变为0X05那么这个值被重置了

同时我们这个时候来看
last insert position
bcview km1.ibd 16 48 2|more
current block:00000003--Offset:00048--cnt bytes:02--data is:00c9
以前这值是
current block:00000003--Offset:00048--cnt bytes:02--data is:0000
而这个值刚好也是 刚才 删除数据后first garbage record offset 的值
current block:00000003--Offset:00044--cnt bytes:02--data is:00c9
而此时值first garbage record offset
bcview km1.ibd 16 44 2|more
变为了
current block:00000003--Offset:00044--cnt bytes:02--data is:007f
这里7f变得更小,这个就是我们id=1的地址,而id=3的地址已经重用了

10、maximum transaction id 
bcview km1.ibd 16 56 8|more
current block:00000003--Offset:00056--cnt bytes:08--data is:0000000000000000

这个值应该代表是所有行中最高的事物ID,但是没有测试出来


11、page level 
 bcview km1.ibd 16 64 2|more
current block:00000003--Offset:00064--cnt bytes:02--data is:0000

代表是索引的层次,这里根节点是页节点是一个节点所以是0

12、index ID 

bcview km1.ibd 16 66 8|more
current block:00000003--Offset:00066--cnt bytes:08--data is:0000000000000255
这是索引的ID这个在INNODB_SYS_INDEXES也是有的。

学习了这些内容,我们有了一些对INDEX PAGE结构的了解。
总结一下:
1、heap top position 是块的高水位,就是索引页曾经达到的最高点。
2、last insert position 为最后一次索引页插入的行的偏移量,如果删除了数据会进行从用,那么这个值和heap top position并没有什么关系。
3、number of record 是块中未删除的数据量行数,每次删除和插入数据一定变化
4、number of heap records/format flag 记录的是 未删除行+删除行+infimum 和supremum的行数 ,未删除行可以重用,所以这个值可能在你插入数据后不会变化。
5、format flag是第15位的值1为compact格式,0为Redundant
6、如果不加入主键,那么会自动生成一个6字节48位的ROWID,它会加大你的存储空间,所以尽可能加入主键吧再建表的时候,建表插入数据后加入主键也不会改善
7、garbage space 就是删除数据DELETE后剩余的空间,随着不断的重用这个空间不断减少,如果没有delete后可以从用的空间为0
8、index ID 这是索引的ID这个在INNODB_SYS_INDEXES也是有的。


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
MySQL底层概述—2.InnoDB磁盘结构
InnoDB磁盘结构主要包括表空间(Tablespaces)、数据字典(Data Dictionary)、双写缓冲区(Double Write Buffer)、重做日志(redo log)和撤销日志(undo log)。其中,表空间分为系统、独立、通用、Undo及临时表空间,分别用于存储不同类型的数据。数据字典从MySQL 8.0起不再依赖.frm文件,转而使用InnoDB引擎存储,支持事务原子性DDL操作。
201 100
MySQL底层概述—2.InnoDB磁盘结构
MySQL底层概述—10.InnoDB锁机制
本文介绍了:锁概述、锁分类、全局锁实战、表级锁(偏读)实战、行级锁升级表级锁实战、间隙锁实战、临键锁实战、幻读演示和解决、行级锁(偏写)优化建议、乐观锁实战、行锁原理分析、死锁与解决方案
MySQL底层概述—10.InnoDB锁机制
MySQL底层概述—5.InnoDB参数优化
本文介绍了MySQL数据库中与内存、日志和IO线程相关的参数优化,旨在提升数据库性能。主要内容包括: 1. 内存相关参数优化:缓冲池内存大小配置、配置多个Buffer Pool实例、Chunk大小配置、InnoDB缓存性能评估、Page管理相关参数、Change Buffer相关参数优化。 2. 日志相关参数优化:日志缓冲区配置、日志文件参数优化。 3. IO线程相关参数优化: 查询缓存参数、脏页刷盘参数、LRU链表参数、脏页刷盘相关参数。
MySQL底层概述—5.InnoDB参数优化
MySQL底层概述—4.InnoDB数据文件
本文介绍了InnoDB表空间文件结构及其组成部分,包括表空间、段、区、页和行。表空间是最高逻辑层,包含多个段;段由若干个区组成,每个区包含64个连续的页,页用于存储多条行记录。文章还详细解析了Page结构,分为通用部分(文件头与文件尾)、数据记录部分和页目录部分。此外,文中探讨了行记录格式,包括四种行格式(Redundant、Compact、Dynamic和Compressed),重点介绍了Compact行记录格式及其溢出机制。最后,文章解释了不同行格式的特点及应用场景,帮助理解InnoDB存储引擎的工作原理。
MySQL底层概述—4.InnoDB数据文件
MySQL底层概述—3.InnoDB线程模型
InnoDB存储引擎采用多线程模型,包含多个后台线程以处理不同任务。主要线程包括:IO Thread负责读写数据页和日志;Purge Thread回收已提交事务的undo日志;Page Cleaner Thread刷新脏页并清理redo日志;Master Thread调度其他线程,定时刷新脏页、回收undo日志、写入redo日志和合并写缓冲。各线程协同工作,确保数据一致性和高效性能。
MySQL底层概述—3.InnoDB线程模型
MySQL底层概述—1.InnoDB内存结构
本文介绍了InnoDB引擎的关键组件和机制,包括引擎架构、Buffer Pool、Page管理机制、Change Buffer、Log Buffer及Adaptive Hash Index。
213 97
MySQL底层概述—1.InnoDB内存结构
MySQL原理简介—2.InnoDB架构原理和执行流程
本文介绍了MySQL中更新语句的执行流程及其背后的机制,主要包括: 1. **更新语句的执行流程**:从SQL解析到执行器调用InnoDB存储引擎接口。 2. **Buffer Pool缓冲池**:缓存磁盘数据,减少磁盘I/O。 3. **Undo日志**:记录更新前的数据,支持事务回滚。 4. **Redo日志**:确保事务持久性,防止宕机导致的数据丢失。 5. **Binlog日志**:记录逻辑操作,用于数据恢复和主从复制。 6. **事务提交机制**:包括redo日志和binlog日志的刷盘策略,确保数据一致性。 7. **后台IO线程**:将内存中的脏数据异步刷入磁盘。
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
MySQL的存储引擎是其核心组件之一,负责数据的存储、索引和检索。不同的存储引擎具有不同的功能和特性,可以根据业务需求 选择合适的引擎。本文详细介绍了MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案。
【MySQL进阶篇】存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
MySQL存储引擎详述:InnoDB为何胜出?
MySQL 是最流行的开源关系型数据库之一,其存储引擎设计是其高效灵活的关键。InnoDB 作为默认存储引擎,支持事务、行级锁和外键约束,适用于高并发读写和数据完整性要求高的场景;而 MyISAM 不支持事务,适合读密集且对事务要求不高的应用。根据不同需求选择合适的存储引擎至关重要,官方推荐大多数场景使用 InnoDB。
88 7
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
220 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等