如何证明INNODB辅助索引叶子结点KEY值相同的按照PRIMARY KEY排序
发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,接http://blog.itpub.net/7728585/viewspace-2126305/RR模式下NEXT-KEY LOCK范围到底有多大证明观点:1、对辅助索引的页中链表进行分析,如果在辅
千家信息网最后更新 2026年11月02日如何证明INNODB辅助索引叶子结点KEY值相同的按照PRIMARY KEY排序接http://blog.itpub.net/7728585/viewspace-2126305/
RR模式下NEXT-KEY LOCK范围到底有多大
证明观点:
1、对辅助索引的页中链表进行分析,如果在辅助索引页内的链表按照首先是KEY排序然后KEY相同的按照PRIMARY KEY排序那么基本就验证了我们的说法
这个随后可以补上
这篇文章用到了自制工具./bcview和./mysqlblock
在网盘
http://pan.baidu.com/s/1num76RJ
同时很多理论知识来自
http://blog.itpub.net/7728585/viewspace-2065464/
http://blog.itpub.net/7728585/viewspace-2063921/
等文章
mysql> create table test (a int,b int,primary key(a),key(b));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into test values(1,1);
Query OK, 1 row affected (0.08 sec)
使用mysqlblock查看得到
current read blocks is : 3 --This Block is data blocks( index pages)!
current read blocks is : 4 --This Block is data blocks( index pages)!
这里面应该是主键的B+树第一个结点和辅助索引B+树的第一个结点
page 4 应该就是辅助索引,我们进行验证查看
从38字节到74字节的是INDEX HEADER,查看他的最后8个字节是index ID
和INNODB_SYS_INDEXES中进行对比
current block:00000003--Offset:00066--cnt bytes:08--data is:0000000000000029
current block:00000004--Offset:00066--cnt bytes:08--data is:000000000000002a
得到INDEX_ID 0X29 0X2A 就是10进制41 42
mysql> select * from information_schema.INNODB_SYS_INDEXES where index_id in (41,42);
+----------+---------+----------+------+----------+---------+-------+-----------------+
| INDEX_ID | NAME | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
+----------+---------+----------+------+----------+---------+-------+-----------------+
| 41 | PRIMARY | 40 | 3 | 1 | 3 | 24 | 50 |
| 42 | b | 40 | 0 | 1 | 4 | 24 | 50 |
+----------+---------+----------+------+----------+---------+-------+-----------------+
2 rows in set (0.01 sec)
查看
mysql> select * from information_schema.INNODB_SYS_TABLES where table_id=40;
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| 40 | test/test | 33 | 5 | 24 | Barracuda | Dynamic | 0 | Single |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
1 row in set (0.02 sec)
可以确定41 42 就是test表的主键和辅助索引,同时确认了current block:00000004就是辅助索引存储数据的
唯一一个叶子结点也是根结点(因为数据很少),
那么我们对page 04进行查看
./bcview test.ibd 16 94 14|more
current block:00000003--Offset:00094--cnt bytes:14--data is:010002001b696e66696d756d0002
current block:00000004--Offset:00094--cnt bytes:14--data is:010002001b696e66696d756d0002
infimum:
010002
001b --偏移量
696e66696d756d0002 --"infimum\0"
确定了第一行的偏移量0X1b级27 级第一行的位置为99+27
./bcview test.ibd 16 126 30|more
current block:00000003--Offset:00126--cnt bytes:21--data is:80000001000000000707a70000011b011080000001
current block:00000004--Offset:00126--cnt bytes:21--data is:800000018000000100000000000000000000000000
这里聚集索引块和辅助索引记录的东西就一样了,
聚集索引page03
80000001000000000707a70000011b011080000001
其中包含了
offset ----cluster key fields (N bytes)
transaction id (6 bytes)
roll pointer (7 bytes)
non-key fields (M bytes)
000000000707a70000011b0110这13个字节就是transaction id 和roll pointer
我们回到主题讨论辅助索引PAGE 4
80000001 b列
80000001 a列
其实就是1和1,第15位的1应该是MYSQL符号位的表示
我们找到了,然后我们插入
insert into test values(5,1);
mysql> insert into test values(5,1);
Query OK, 1 row affected (0.03 sec)
mysql> commit;
通过偏移量进行找到这个记录
[root@ora12ctest test]# ./bcview test.ibd 16 124 2|more
current block:00000004--Offset:00124--cnt bytes:02--data is:000e
偏移量0X0E就是14
那么5 1 在辅助索引页PAGE 4中的位置是126+14=140
./bcview test.ibd 16 140 30|more
current block:00000004--Offset:00140--cnt bytes:30--data is:800000018000000500000000000000000000000000000000000000000000
80000001 b列
80000005 a列
这个时候实际上是 (B:1 A:1)-->(B:1 A:5)
这个时候我们插入
mysql> insert into test values(3,1);
Query OK, 1 row affected (0.00 sec)
回过头我们再次查看第一条记录(B:1,A:1)下一条记录的便宜量
[root@ora12ctest test]# ./bcview test.ibd 16 124 2|more
current block:00000004--Offset:00124--cnt bytes:02--data is:001c
发现已经改变了变为了0X1C为28我们找一下看看是不是我们新插入的(B:1,A:3)
126+28=154
./bcview test.ibd 16 154 20|more
current block:00000004--Offset:00154--cnt bytes:20--data is:8000000180000003
没有问题,在查看这条记录的下一条的偏移量
current block:00000004--Offset:00152--cnt bytes:02--data is:fff2
我们发现fff2明显是负数 补码存在转换为负数为-14
则下一条就是
154-14=140
查看就是
[root@ora12ctest test]# ./bcview test.ibd 16 140 10|more
current block:00000004--Offset:00140--cnt bytes:20--data is:8000000180000005
我们找到了(B:1,A:5)的这条记录。
那么原始的(B:1 A:1)-->(B:1 A:5) 由于(B:1 A:3)的加入变为了
(B:1 A:1)-->(B:1 A:3)-->(B:1 A:5)
由此证明了我们的观点,就是在B+数的叶子结点如果先按照辅助索引的KEY值
排序然后按照PRIMARY的值排序。及order by 辅助索引KEY,primary key
刚才肉眼已经看到了(B:1 A:1)-->(B:1 A:3)-->(B:1 A:5)
然我们在加入一些无规则的来看看。
mysql> insert into test values(4,2);
Query OK, 1 row affected (0.59 sec)
mysql> insert into test values(10,4);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(7,4);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(8,5);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(11,5);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(20,6);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(21,6);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(19,7);
Query OK, 1 row affected (0.03 sec)
mysql> insert into test values(16,7);
Query OK, 1 row affected (0.01 sec)
用程序跑一下看看
[root@ora12ctest test]# ./a.out test.ibd 4
Index_no is:42
find first one record!
B:1,A:1-->
B:1,A:3-->
B:1,A:5-->
B:2,A:4-->
B:4,A:7-->
B:4,A:10-->
B:5,A:8-->
B:5,A:11-->
B:6,A:20-->
B:6,A:21-->
B:7,A:16-->
B:7,A:19-->
显然程序的运行也验证我们的结果。。我们插入的顺序是无序的,但是查看到的是
辅助索引按照B列排序相同的按照主键A进行排序。
本程序只能用于这个列子,并且数据量不多,如果造成了B+树索引分裂肯定不行,并且插入的值必须为
正数不要为负数和0,INNODB中正数的最高为符号为1这个和C/C++不同,暂时没有找到他的计算方式
所以简单的用A^0X80000000来得到,同时只能是Little_endian 平台 如LINUX
首先你要使用./bcview和./mysqlblock
来确定辅助索引的PAGE NO才行,就像上面说的。然后使用是 ./a.out test.ibd 4 4就是找到的page号。
表必须是:
create table test (a int,b int,primary key(a),key(b));
单独表空间。因为我任何地方都是写死了的,活的只有读取叶子结点内的链表结构而已。我在5.7 INNODB引擎执行没有问题。
行格式为:
mysql> select * from INNODB_SYS_TABLES where name='test/test'
-> ;
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| 40 | test/test | 33 | 5 | 24 | Barracuda | Dynamic | 0 | Single |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
但是应该在5.6 INNODB默认的行格式下也没问题,但是没测试过。
附上代码很简单:
编译用gcc test.c 得到a.out跑就行了.
是 ./a.out test.ibd 4
这里引入另外一个问题
MYSQL中表记录返回的顺序问题。详细参考下面:
http://blog.itpub.net/7728585/viewspace-2126470/
RR模式下NEXT-KEY LOCK范围到底有多大
证明观点:
1、对辅助索引的页中链表进行分析,如果在辅助索引页内的链表按照首先是KEY排序然后KEY相同的按照PRIMARY KEY排序那么基本就验证了我们的说法
这个随后可以补上
这篇文章用到了自制工具./bcview和./mysqlblock
在网盘
http://pan.baidu.com/s/1num76RJ
同时很多理论知识来自
http://blog.itpub.net/7728585/viewspace-2065464/
http://blog.itpub.net/7728585/viewspace-2063921/
等文章
mysql> create table test (a int,b int,primary key(a),key(b));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into test values(1,1);
Query OK, 1 row affected (0.08 sec)
使用mysqlblock查看得到
current read blocks is : 3 --This Block is data blocks( index pages)!
current read blocks is : 4 --This Block is data blocks( index pages)!
这里面应该是主键的B+树第一个结点和辅助索引B+树的第一个结点
page 4 应该就是辅助索引,我们进行验证查看
从38字节到74字节的是INDEX HEADER,查看他的最后8个字节是index ID
和INNODB_SYS_INDEXES中进行对比
current block:00000003--Offset:00066--cnt bytes:08--data is:0000000000000029
current block:00000004--Offset:00066--cnt bytes:08--data is:000000000000002a
得到INDEX_ID 0X29 0X2A 就是10进制41 42
mysql> select * from information_schema.INNODB_SYS_INDEXES where index_id in (41,42);
+----------+---------+----------+------+----------+---------+-------+-----------------+
| INDEX_ID | NAME | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
+----------+---------+----------+------+----------+---------+-------+-----------------+
| 41 | PRIMARY | 40 | 3 | 1 | 3 | 24 | 50 |
| 42 | b | 40 | 0 | 1 | 4 | 24 | 50 |
+----------+---------+----------+------+----------+---------+-------+-----------------+
2 rows in set (0.01 sec)
查看
mysql> select * from information_schema.INNODB_SYS_TABLES where table_id=40;
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| 40 | test/test | 33 | 5 | 24 | Barracuda | Dynamic | 0 | Single |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
1 row in set (0.02 sec)
可以确定41 42 就是test表的主键和辅助索引,同时确认了current block:00000004就是辅助索引存储数据的
唯一一个叶子结点也是根结点(因为数据很少),
那么我们对page 04进行查看
./bcview test.ibd 16 94 14|more
current block:00000003--Offset:00094--cnt bytes:14--data is:010002001b696e66696d756d0002
current block:00000004--Offset:00094--cnt bytes:14--data is:010002001b696e66696d756d0002
infimum:
010002
001b --偏移量
696e66696d756d0002 --"infimum\0"
确定了第一行的偏移量0X1b级27 级第一行的位置为99+27
./bcview test.ibd 16 126 30|more
current block:00000003--Offset:00126--cnt bytes:21--data is:80000001000000000707a70000011b011080000001
current block:00000004--Offset:00126--cnt bytes:21--data is:800000018000000100000000000000000000000000
这里聚集索引块和辅助索引记录的东西就一样了,
聚集索引page03
80000001000000000707a70000011b011080000001
其中包含了
offset ----cluster key fields (N bytes)
transaction id (6 bytes)
roll pointer (7 bytes)
non-key fields (M bytes)
000000000707a70000011b0110这13个字节就是transaction id 和roll pointer
我们回到主题讨论辅助索引PAGE 4
80000001 b列
80000001 a列
其实就是1和1,第15位的1应该是MYSQL符号位的表示
我们找到了,然后我们插入
insert into test values(5,1);
mysql> insert into test values(5,1);
Query OK, 1 row affected (0.03 sec)
mysql> commit;
通过偏移量进行找到这个记录
[root@ora12ctest test]# ./bcview test.ibd 16 124 2|more
current block:00000004--Offset:00124--cnt bytes:02--data is:000e
偏移量0X0E就是14
那么5 1 在辅助索引页PAGE 4中的位置是126+14=140
./bcview test.ibd 16 140 30|more
current block:00000004--Offset:00140--cnt bytes:30--data is:800000018000000500000000000000000000000000000000000000000000
80000001 b列
80000005 a列
这个时候实际上是 (B:1 A:1)-->(B:1 A:5)
这个时候我们插入
mysql> insert into test values(3,1);
Query OK, 1 row affected (0.00 sec)
回过头我们再次查看第一条记录(B:1,A:1)下一条记录的便宜量
[root@ora12ctest test]# ./bcview test.ibd 16 124 2|more
current block:00000004--Offset:00124--cnt bytes:02--data is:001c
发现已经改变了变为了0X1C为28我们找一下看看是不是我们新插入的(B:1,A:3)
126+28=154
./bcview test.ibd 16 154 20|more
current block:00000004--Offset:00154--cnt bytes:20--data is:8000000180000003
没有问题,在查看这条记录的下一条的偏移量
current block:00000004--Offset:00152--cnt bytes:02--data is:fff2
我们发现fff2明显是负数 补码存在转换为负数为-14
则下一条就是
154-14=140
查看就是
[root@ora12ctest test]# ./bcview test.ibd 16 140 10|more
current block:00000004--Offset:00140--cnt bytes:20--data is:8000000180000005
我们找到了(B:1,A:5)的这条记录。
那么原始的(B:1 A:1)-->(B:1 A:5) 由于(B:1 A:3)的加入变为了
(B:1 A:1)-->(B:1 A:3)-->(B:1 A:5)
由此证明了我们的观点,就是在B+数的叶子结点如果先按照辅助索引的KEY值
排序然后按照PRIMARY的值排序。及order by 辅助索引KEY,primary key
刚才肉眼已经看到了(B:1 A:1)-->(B:1 A:3)-->(B:1 A:5)
然我们在加入一些无规则的来看看。
mysql> insert into test values(4,2);
Query OK, 1 row affected (0.59 sec)
mysql> insert into test values(10,4);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(7,4);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(8,5);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(11,5);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(20,6);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test values(21,6);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values(19,7);
Query OK, 1 row affected (0.03 sec)
mysql> insert into test values(16,7);
Query OK, 1 row affected (0.01 sec)
用程序跑一下看看
[root@ora12ctest test]# ./a.out test.ibd 4
Index_no is:42
find first one record!
B:1,A:1-->
B:1,A:3-->
B:1,A:5-->
B:2,A:4-->
B:4,A:7-->
B:4,A:10-->
B:5,A:8-->
B:5,A:11-->
B:6,A:20-->
B:6,A:21-->
B:7,A:16-->
B:7,A:19-->
显然程序的运行也验证我们的结果。。我们插入的顺序是无序的,但是查看到的是
辅助索引按照B列排序相同的按照主键A进行排序。
本程序只能用于这个列子,并且数据量不多,如果造成了B+树索引分裂肯定不行,并且插入的值必须为
正数不要为负数和0,INNODB中正数的最高为符号为1这个和C/C++不同,暂时没有找到他的计算方式
所以简单的用A^0X80000000来得到,同时只能是Little_endian 平台 如LINUX
首先你要使用./bcview和./mysqlblock
来确定辅助索引的PAGE NO才行,就像上面说的。然后使用是 ./a.out test.ibd 4 4就是找到的page号。
表必须是:
create table test (a int,b int,primary key(a),key(b));
单独表空间。因为我任何地方都是写死了的,活的只有读取叶子结点内的链表结构而已。我在5.7 INNODB引擎执行没有问题。
行格式为:
mysql> select * from INNODB_SYS_TABLES where name='test/test'
-> ;
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | SPACE_TYPE |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
| 40 | test/test | 33 | 5 | 24 | Barracuda | Dynamic | 0 | Single |
+----------+-----------+------+--------+-------+-------------+------------+---------------+------------+
但是应该在5.6 INNODB默认的行格式下也没问题,但是没测试过。
附上代码很简单:
点击(此处)折叠或打开
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- void* reverse(void* p,int length) //Little_endian reverse
- {
- int i;
- char* s= (char*)(p);
- char* temp = (char*)calloc(1,length);
- memcpy(temp,s,length);
- for(i=0;i<length;i++)
- {
- s[i] = temp[length-1-i];
- }
- free(temp);
- temp=NULL;
- return p;
- }
- int main(int argc,char *argv[])
- {
- FILE* fd;
- long blofset;
- short level;
- long int index_no;
- short initof;
- int B;
- int A;
- int reofset;
- if(argc != 3 )
- {
- printf("USEAGE ERROR useage:./tool dbf pageno\n");
- exit(3);
- }
- if(!(fd = fopen(argv[1],"r")))
- {
- perror("error:");
- exit(1);
- }
- sscanf(argv[2],"%ld",&blofset);
- fseek(fd,blofset*16*1024,SEEK_SET);
- fseek(fd,64,SEEK_CUR);
- fread(&level,2,1,fd);
- fread(&index_no,8,1,fd);
- reverse(&level,2);
- reverse(&index_no,8);
- fseek(fd,23,SEEK_CUR);
- fread(&initof,2,1,fd);
- reverse(&initof,2);
- printf("Index_no is:%ld\n",index_no);
- if(initof != 0 )
- {
- printf("find first one record!\n");
- while(1)
- {
- fseek(fd,initof-2,SEEK_CUR);
- fread(&initof,2,1,fd);
- reverse(&initof,2);
- if(initof == 0)
- {
- break;
- }
- else
- {
- fread(&B,4,1,fd);
- fread(&A,4,1,fd);
- fseek(fd,-8,SEEK_CUR);
- reverse(&B,4);
- reverse(&A,4);
- A=A^0X80000000;
- B=B^0X80000000;
- printf("B:%d,A:%d-->\n",B,A);
- }
- }
- }
- else
- {
- printf("no record find!\n");
- exit(2);
- }
- }
编译用gcc test.c 得到a.out跑就行了.
是 ./a.out test.ibd 4
这里引入另外一个问题
MYSQL中表记录返回的顺序问题。详细参考下面:
http://blog.itpub.net/7728585/viewspace-2126470/
索引
辅助
就是
结点
排序
问题
偏移
字节
叶子
同时
数据
程序
负数
验证
相同
一行
位置
时候
格式
正数
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
咖啡网
互联网络科技
互联网科技股
伟宏互联网科技
互联网金融监管科技数据
金诺互联网科技
互联网科技开发公司
互联网科技公司官网
融势互联网科技
重庆威客帮互联网科技
互联网科技教育视频
互联网大会黑科技排名
宁夏科技产业互联网案例
珠海东科互联网科技有限公司
福州德业互联网科技
版纳互联网科技选哪家
科技互联网专业务虚会材料
重庆科技产业互联网有哪些
互联网科技创新方面的资料
知域互联网科技有限公司官网
狮子座互联网科技有限公司
亿账通互联网科技
互联网 视角下的科技创新
天扬科技互联网广告
海南科技产业互联网平台
深圳市运趣互联网科技有限公司
互联网科技博主是什么意思
南平创想时代互联网科技有限公司
辽宁互联网新科技
利用互联网等科技手段