千家信息网

如何证明INNODB辅助索引叶子结点KEY值相同的按照PRIMARY KEY排序

发表于:2025-02-07 作者:千家信息网编辑
千家信息网最后更新 2025年02月07日,接http://blog.itpub.net/7728585/viewspace-2126305/RR模式下NEXT-KEY LOCK范围到底有多大证明观点:1、对辅助索引的页中链表进行分析,如果在辅
千家信息网最后更新 2025年02月07日如何证明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默认的行格式下也没问题,但是没测试过。

附上代码很简单:

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>

  4. void* reverse(void* p,int length) //Little_endian reverse
  5. {
  6. int i;
  7. char* s= (char*)(p);
  8. char* temp = (char*)calloc(1,length);
  9. memcpy(temp,s,length);


  10. for(i=0;i<length;i++)
  11. {
  12. s[i] = temp[length-1-i];
  13. }
  14. free(temp);
  15. temp=NULL;
  16. return p;
  17. }



  18. int main(int argc,char *argv[])
  19. {
  20. FILE* fd;
  21. long blofset;
  22. short level;
  23. long int index_no;
  24. short initof;
  25. int B;
  26. int A;
  27. int reofset;


  28. if(argc != 3 )
  29. {
  30. printf("USEAGE ERROR useage:./tool dbf pageno\n");
  31. exit(3);
  32. }

  33. if(!(fd = fopen(argv[1],"r")))
  34. {
  35. perror("error:");
  36. exit(1);
  37. }

  38. sscanf(argv[2],"%ld",&blofset);
  39. fseek(fd,blofset*16*1024,SEEK_SET);
  40. fseek(fd,64,SEEK_CUR);
  41. fread(&level,2,1,fd);
  42. fread(&index_no,8,1,fd);
  43. reverse(&level,2);
  44. reverse(&index_no,8);
  45. fseek(fd,23,SEEK_CUR);
  46. fread(&initof,2,1,fd);
  47. reverse(&initof,2);
  48. printf("Index_no is:%ld\n",index_no);
  49. if(initof != 0 )
  50. {
  51. printf("find first one record!\n");
  52. while(1)
  53. {
  54. fseek(fd,initof-2,SEEK_CUR);
  55. fread(&initof,2,1,fd);
  56. reverse(&initof,2);
  57. if(initof == 0)
  58. {
  59. break;
  60. }
  61. else
  62. {
  63. fread(&B,4,1,fd);
  64. fread(&A,4,1,fd);
  65. fseek(fd,-8,SEEK_CUR);
  66. reverse(&B,4);
  67. reverse(&A,4);
  68. A=A^0X80000000;
  69. B=B^0X80000000;
  70. printf("B:%d,A:%d-->\n",B,A);
  71. }

  72. }
  73. }
  74. else
  75. {
  76. printf("no record find!\n");
  77. exit(2);
  78. }
  79. }

编译用gcc test.c 得到a.out跑就行了.
./a.out test.ibd 4

这里引入另外一个问题
MYSQL中表记录返回的顺序问题。详细参考下面:
http://blog.itpub.net/7728585/viewspace-2126470/
索引 辅助 就是 结点 排序 问题 偏移 字节 叶子 同时 数据 程序 负数 验证 相同 一行 位置 时候 格式 正数 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 数据库基础实训7作业 我的世界求炎服务器 北京雨辰网络技术培训学校 双11互联网科技股 软件开发在哪个学校就业好 拨打对方号码显示无法连接服务器 新加坡网络安全战 gdc服务器硬盘放映 区块链网络安全监测平台 学校日常办公中网络安全应用 服务器机房建设防火标准 网络技术方面找工作 深圳市天众互联网络科技有限公司 网络安全李嘉 中兴给我打电话换软件开发岗 青岛清算中心网络安全建设项目 提升服务器的运用效率 软件开发做安卓 关于网络安全的手抄报素材 特斯拉中国的数据库已经建成了吗 路由服务器辐射大吗 数据库 占用cpu过高 小学会用什么网络安全设备 u8数据库怎么看所有单据 dns辅服务器未响应怎么解决 项目管理与软件开发管理 增城区数据网络技术开发商家 网络安全作业标准 软件开发属不属工程类 悉尼大学的计算机网络安全硕士
0