解析innodb表的索引结构

说明:本次测试的版本是mysql 5.7.23 由于本人水平有限,有错误的地方还请大家帮忙指正.
我们知道innodb表的数据是全部存储聚簇索引中的,非主键索引称为二级索引.不管是二级索引还是聚簇索引都是B+树的存储结构.为方便展示,设置innodb_file_per_table=ON
下面介绍聚簇索引和二级索引的存储结构:

1.自定义主键的聚簇索引

叶子节点的索引结构:[主键列][DB_TRX_ID][DB_POLL_PTR][其他创建表的非主键列]
内节点的索引结构:[主键列][PAGE_NO]
其中DB_TRX_ID:表示的事务ID
DB_POLL_PTR:表示的是undo记录的地址,对于怎样解析undo地址,后续介绍.
造测试数据
create table zdr_test_dump(id int(10) unsigned NOT NULL AUTO_INCREMENT,
c1 int(10) unsigned NOT NULL default 0,
c2 char(255) not null,
c3 char(255) not null,
c4 char(255) not null,
PRIMARY KEY(id,c2),
KEY c1(c1,c3));
delimiter ;;
create procedure loop_insert()
BEGIN
set @x =0;
set @uuid1=uuid();
set @uuid2=uuid();
ins: LOOP
set @x = @x + 1;
IF @x = 200 then
leave ins;
END IF;
insert into zdr_test_dump select 0,round(rand()*1024),
@uuid1,concat(@uuid1,@uuid2),concat(@uuid1,@uuid2);
END LOOP ins;
commit;
END;
;;

这里使用自己编译新增的命令,打印该表的聚簇索引.
使用 set global innodb_zdr_dump_indextree=index_id;命令 会将对应的索引结构输出到errlog目录下的一个新.trc 文件中
使用set global innodb_zdr_dump_btreenode='space_id,page_no';命令 会将表空间的space_id的第page_no 个page的内容输出到errlog目录下的.trc文件中

索引结构.png

然后使用set global innodb_zdr_dump_indextree=41; 命令 这里的41是zdr_test_dump表的主键索引的INDEX_ID
自定义主键索引结构输出文件名.png

然后我们看dump_indextree_26_41.trc 文件(26表示的是zdr_test_dump表所属的表空间ID 即space_id 41表示的INDEX_ID)内容
自定义主键索引结构.png

内容解析:
branch:[0x7f43ac514000][3]level:1 表示的是一个B+树的一个节点也就是一个页(page),一个innodb的page 大小有4K 8K 16K 32K 64K 不同的值.每个page都有一个page_no(从0开始)并且该page_no存储在其对应的page页的特定的位置(后续page内容分析时候再做详述).
branch 表示这个节点是内节点,leaf 表示叶子节点
0x7f43ac514000 表示这个节点的内存地址
[3]表示这个节点的page_no,
level 表示这个节点在整个B+树中的层级(level=节点高度-1).
这里我们知道branch:[0x7f43ac514000][3]level:1 是根节点也是B+树的内节点.
我们可以看下内节点的索引结构:
set global innodb_zdr_dump_btreenode='26,3';
自定义主键dump_page文件名.png

查看文件内容
自定义主键索引内节点.png

col 0: nm:[id] len: 4 ----col 0 表示记录的字段下标 nm:表示字段名 len:表示字段存储数据的所占的字节数
00 00 00 0a ------字段所存储的数据 十六进制数
我们再使用set global innodb_zdr_dump_btreenode='26,6'; 查看叶子节点的内容
自定义主键索引叶子节点.png

字段解释:
col 2: nm:[DB_TRX_ID] len: 6 ---这条记录最后一次写的事务ID
00 00 00 00 05 07----十六进制
col 3: nm:[DB_ROLL_PTR] len: 7 这条记录对应的undo记录的信息
insert:1 space_id:1 page_no:37 offset:2693 insert表示该条记录是INSERT还是UPDATE offset:表示对应的undo在space_id=1 page_no=37 页中的偏移位置

2.自定义主键的二级非唯一索引

叶子节点KEY列:[非唯一索引列][主键列]
内节点KEY列:[非唯一索引列][主键列][PAGE_NO]
使用set global innodb_zdr_dump_indextree=42;命令 打印二级索引的结构

自定义主键二级索引.png

我们知道page_no=4 是二级索引的内节点同时也是根节点
执行set global innodb_zdr_dump_btreenode='26,4';
我们查看文件内容
自定义主键二级索引内节点.png

内节点KEY列确实为[非唯一索引列][主键列][PAGE_NO]
我们看下非唯一二级索引的叶子节点的记录格式:
执行set global innodb_zdr_dump_btreenode='26,8';
查看文件内容:
自定义主键二级非唯一索引叶子节点.png

叶子节点列确实为[非唯一索引列][主键列]

3.自定义主键的二级唯一索引

叶子节点KEY列:[唯一索引列][主键列]
内节点KEY列:[唯一索引列][主键列][PAGE_NO]
create table zdr_test_dump1(id int(10) unsigned NOT NULL AUTO_INCREMENT,
c1 int(10) unsigned NOT NULL default 0,
c2 char(255) not null,
c3 char(255) not null,
c4 char(255) not null,
PRIMARY KEY(id,c2),
UNIQUE KEY c1(c1,c3));
delimiter ;;
create procedure loop_insert1()
BEGIN
set @x =0;
set @uuid1=uuid();
set @uuid2=uuid();
ins: LOOP
set @x = @x + 1;
IF @x = 200 then
leave ins;
END IF;
insert into zdr_test_dump1 select 0,@x,
@x,concat(@x,@x),concat(@x,@x);
END LOOP ins;
commit;
END;
;;
新增数据之后
执行set global innodb_zdr_dump_indextree=44;命令查询二级唯一索引结构

自定义主键二级唯一索引.png

我们执行set global innodb_zdr_dump_btreenode='27,4';
查看内节点的KEY列
自定义主键二级唯一索引内节点.png

我们执行set global innodb_zdr_dump_btreenode='27,8';
命令查看二级唯一索引的叶子节点内容:
自定义主键二级唯一索引叶子节点.png

结论:
叶子节点KEY列:[唯一索引列][主键列]
内节点KEY列:[唯一索引列][主键列][PAGE_NO]

4.未定义主键的聚簇索引

叶子节点KEY列:[DB_ROW_ID][DB_TRX_ID][DB_POLL_PTR][表中的其他所有列]
内节点KEY列:[DB_ROW_ID][CHILD_PAGENO]
create table zdr_test_dump_noclust(
c1 int(10) unsigned default 0,
c2 char(255) ,
c3 char(255) ,
c4 char(255) ,
UNIQUE KEY c12(c1,c2));
delimiter ;;
create procedure loop_insert2()
BEGIN
set @x =0;
set @uuid1=uuid();
set @uuid2=uuid();
ins: LOOP
set @x = @x + 1;
IF @x = 200 then
leave ins;
END IF;
insert into zdr_test_dump_noclust select @x,
@x,concat(@x,@x),concat(@x,@x);
END LOOP ins;
commit;
END;
;;
插入数据之后 执行set global innodb_zdr_dump_indextree=45;查看聚簇索引结构

未定义主键聚簇索引.png

我们知道space_id=28 page_no=3为聚簇索引的内节点
执行set global innodb_zdr_dump_btreenode='28,3';查看内节点内容
未定义主键聚簇索引内节点.png

其数据为[DB_ROW_ID][CHILD_PAGE_NO]
row#1 del:0 n_owned:0 heap_no:2 current_offs:126 next_record=142
col 0: nm:[DB_ROW_ID] len: 6 ---未定义主键的innodb表,会自动创建一个DB_ROW_ID作为主键,该主键的值是系统内唯一且单调递增,但是对于同一条记录主从库的DB_ROW_ID可能不同,所以建议创建表的过程中都自定义主键
00 00 00 00 02 00
col 1: nm: [child_page_no] len: 4
00 00 00 05
我们执行set global innodb_zdr_dump_btreenode='28,6'; 查看叶子节点的KEY列
未定义主键聚簇索引叶子节点.png

结论:
叶子节点KEY列:[DB_ROW_ID][DB_TRX_ID][DB_POLL_PTR][表中的其他所有列]
内节点KEY列:[DB_ROW_ID][CHILD_PAGENO]

5.未定义主键二级唯一索引

叶子节点KEY列:[二级唯一索引列][DB_ROW_ID]
内节点KEY列:[二级唯一索引列][DB_ROW_ID][PAGE_NO]
执行set global innodb_zdr_dump_indextree=46;查看未定义主键的二级唯一索引c12

未定义主键二级唯一索引.png

我们知道space_id=28,page_no=4 是二级唯一索引的内节点
执行set global innodb_zdr_dump_btreenode='28,4';查询二级唯一索引内节点
未定义主键二级唯一索引内节点.png

KEY列是:[二级唯一索引列][DB_ROW_ID][PAGE_NO]
我们知道space_id=28,page_no=9 是二级唯一索引的叶子节点
执行set global innodb_zdr_dump_btreenode='28,9';查看二级唯一索引叶子节点内容
未定义主键二级唯一索引叶子节点.png

结论:叶子节点KEY列:[二级唯一索引列][DB_ROW_ID]
内节点KEY列:[二级唯一索引列][DB_ROW_ID][PAGE_NO]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容