文章目录
- 创建新表页的信息
- 新增一条数据
- 根据页号找数据信息
- 脚本代码
- py_innodb_page_info
- 根据地址计算页号
- 根据页号计算起始地址
主要介绍表空间索引页里面有哪些内容,数据在表空间文件里面是怎么组织的
创建新表页的信息
CREATE TABLE `test8` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL DEFAULT '' COMMENT '姓名',`finish` tinyint(1) DEFAULT '0' COMMENT '完成状态',`uid` varchar(64) NOT NULL DEFAULT '' COMMENT '用户ID信息',`external1` varchar(512) NOT NULL DEFAULT '' COMMENT '大字段信息1',`external2` varchar(512) NOT NULL DEFAULT '' COMMENT '大字段信息2',`external3` varchar(512) NOT NULL DEFAULT '' COMMENT '大字段信息3',`external4` varchar(512) NOT NULL DEFAULT '' COMMENT '大字段信息4',`external5` varchar(512) NOT NULL DEFAULT '' COMMENT '大字段信息5',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '缓存时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试信息表8';
新建一个测试表test8
,然后看看缓冲池里的页的变化。把表test8
的一些页加载进来了,看最后一列INDEX_NAME
有个PRIMARY
、idx_name
两个索引的名称,一个是主键索引,一个是辅助索引;因为InnoDB
是聚簇索引形式的,主键索引的叶子节点就包含了数据。
FILE_SPACE_HEADER
页增加了1个,是把test8
的FILE_SPACE_HEADER
页加载进来了,IBUF_BITMAP
页多了7个是除了加载了test8
的这个页,还加载了其他test
数据库下的表进来…
再看这个表空间里面有什么,7个页112k,MySQL
初始创建表不是只有96k么?为啥这多了16k;MySQL
建一个一般的表确实只给6个页的空间;但是我们这边张表多了个索引,它就给索引也分配了一个页。试了下如果两个索引的话,会多给两个页,就是多几个索引就多几个页。
使用命令hexdump -C test8.ibd
输出页格式化的二进制信息;页的类型信息在第25,26两个字节的位置。
截图里面的 * 号代表这一行的数据和上一行一样,省略了
主键索引页和辅助索引页类型的值都是0x45bf
,所以他们都是INDEX
页,主键索引叶子节点会存放数据,辅助索引就是单纯的辅助索引,要整行数据需要再到主键索引下去找。
所有的页面类型信息,见源码storage/innobase/include/fil0fil.h
新增一条数据
INSERT INTO `test8` (`name`, `finish`, `uid`, `external1`, `external2`, `external3`, `external4`, `external5`, `create_time`)
VALUES('name001', 0, 'uid001', 'aaaaaaaa', 'bbbbbbbb', 'cccccccc', 'dddddddd', 'eeeeeeee', '2024-08-04 18:09:35');
页还是那么几个,没什么变化,NEWEST_MODIFICATION
变化了,这代表LSN
号;我们每次提交事务的时候,数据都会刷新到redo log里面,会有这个日志序列号LSN
,代表页面有变化了;行数就像我们看到的1行,数据的大小变了。
LSN
在页中的位置是页面类型前面的8个字节,可以自己输出看看文件里面的前8个字节的数转换成十进制是不是这么多。
再用hexdump
命令看看test8.ibd
文件
主键索引页的大小92个字节:画红线的字节前面7个字节是varchar
字符串的这个记录每个信息的长度,逆序存放的的;再后面1个字节是代表哪个位置为null
的,后面5个字节是记录头信息;第一个蓝线是主键ID,紧接着是Transaction ID
和Roll Pointer
,最后画红线的是时间字段信息,剩下的看得出来是我们插入的记录,加起来92个字节
辅助索引页的大小21个字节:前面6个字节varchar
的长度以及记录头信息,索引字段name001
7个字节,主键ID 8个字节,加起来21个字节。
下面我们到一个数据多一点的表里面去找找数据
根据页号找数据信息
我这边前面测试的时候建过一个test2
表,插入了上百万条数据,我们看看缓冲池里面加载了些什么数据进来,这是目前在缓冲池里面的页的数据
我们看看页号101的数据是哪些数据,计算出它的起始地址是0x194000
,它是一个INDEX
页,独立表空间里面基本上都是索引页了;0x1242
的十进制是4674;查询出来就是这条数据了
我们再找个二级索引页,执行下索引列的统计sql
,MySQL
缓冲池就会把索引页加载进来了
我们看看页号23751的数据是哪些数据,计算出它的起始地址是0x1731c000
,它是一个二级索引页(第56-64个字节有值,就是二级索引页,表示修改当前页的最大事务ID,仅在二级索引中定义,聚簇索引没有),独立表空间里面基本上都是数据页了;0x03e7cf
的十进制是255951;查询出来这行数据的索引列就是这个
好了,差不多就写这么多了,还有不少其他不明白的细节,以后再慢慢了解吧!
- mysql的有符号正数,为什么最高位是1?
脚本代码
py_innodb_page_info
https://github.com/yjysanshu/py_innodb_page_info
根据地址计算页号
page_size_bytes = 16 * 1024 # 16k# hexdump 打印出来的地址
hex_address = "00004010"
address = int(hex_address, 16)print("页号: " + str(address // page_size_bytes))
print("偏移地址: " + str(hex(address % page_size_bytes)))
根据页号计算起始地址
page_no = 23502
print(hex(page_no * page_size_bytes))
!!!