数据库
首页 > 数据库> > 动手实验查看MySQL索引的B+树的高度

动手实验查看MySQL索引的B+树的高度

作者:互联网

一:

简化几个概念:
h:统称索引的高度;
h1:聚簇索引的高度;
h2:二级辅助索引的高度;
k:中间结点的扇出系数。

二:索引结构

索引结构
叶子节点其实是双向链表,而叶子节点内的行数据是单向链表,该图未体现。
image
磁盘块其实是页,用操作系统中的术语来表达而已。
InnoDB中使用的是B+树聚集索引,主键索引叶子节点有整行的数据,辅助索引有主键值(用于回表查询)和索引值。

2.1 页的概念

Mysql的InnoDB是以页为存储单位的,每个B+Tree的节点都是一个页的大小,默认一页的大小是16K(与操作系统数据读取相关)。

数据页>
数据页(即有行数据的叶子节点)

索引页和数据页

2.2 索引高度h与页面I/O数的关系

每次查询都要访问到叶子结点,其访问的页面数正好就是索引的高度h。例如,一次主键上的点查询SELECT * FROM USER WHERE id=1,那么要查询h1个页面才能找到叶子结点里的行数据,也即进行h1次页面I/O。(另外,二级索引基本都加载在内存里了,这里我们暂忽略这种情况。)

综上,查询对应的页面I/O数跟利用的索引有关,主要分为以下几种情况:

2.3 索引高度理论计算

索引页(非叶子节点)中可以分割为多个扇区,每个扇区再指向某子节点(某页)。
假设非叶子节点扇区数为k个、高度h、叶子结点的行记录数为n,则叶子结点数为k(h-1),总记录数为k(h-1)*n。
InnoDB每个页面默认16KB,假设主键是4B的int类型。对于非叶子节点,每个主键值后有个页号4B,还有6B的其他数据(参考《MySQL技术内幕:InnoDB存储引擎》),那么扇区个数k=16KB/(4B+4B+6B)≈1170。
假设每行记录大小为1KB,则每个叶子结点可以容纳的记录数n=16KB/1KB=16。

在高度h=3时,叶子结点数=1170^2 ≈137W,总记录数=1170^2*16=2190W!!也就是说,InnoDB通过三次索引页面的I/O,即可索引2190W行记录。

同理,在高度h=4时,总行数=1170^3*16≈256亿条!

三、动手查看索引真实高度

image

页的Page Header包含一个PAGE_LEVEL的信息,用于表示当前页所在索引中的高度。默认叶子节点的高度为0,那么Root页(根节点)的PAGE_LEVEL+1就是这棵索引的高度。

image

**怎样得到一张含有所有索引的Root页所在的位置的表呢?在《MySQL技术内幕:InnoDB存储引擎》书中分析过<space,3>这个页(即ibd文件的第3个页面,从0开始)是聚簇索引的Root页,在《MySQL内核:InnoDB存储引擎 卷1》中也分析,Root页的位置通常是不会更改的。那么其他索引的Root页所在的位置呢?通过下面的SQL语句可以查出表中各索引的Root页信息:

SELECT b.name, a.name, index_id, type, a.space, a.PAGE_NO FROM information_schema.INNODB_SYS_INDEXES a, information_schema.INNODB_SYS_TABLES b WHERE a.table_id = b.table_id AND a.space <> 0;

image

其中<space,page_no>就是索引的Root页信息,SPACE可以认为是表的ibd文件,PAGE_NO代表ibd文件中的页面号(从0开始)。有了这些信息就可以方便的定位了,因为PAGE_LEVEL在每个Root页的偏移量64位置处,占用两个字节,这样我们通过hexdump(show global variables like "%datadir%"查看MySQL数据文件位置)就可以快速定位到各索引树的高度信息了。例如,我们通过如下命令查看guli/edu_course表主键索引的高度: `$hexdump -C -s 49216 -n 10 edu_course.ibd`

标签:结点,查看,高度,叶子,索引,MySQL,Root,节点
来源: https://www.cnblogs.com/BetterCallSaul/p/16592592.html