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

一:文中几个概念

h:统称索引的高度;
h1:主键索引的高度;
h2:辅助索引的高度;
k:非叶子节点扇区个数。

二:索引结构

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

2.1 页的概念

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

动手实验查看MySQL索引的B+树的高度
数据页(即叶子节点)

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

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

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

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

  • 点查询:
  • 聚族索引:h1
  • 二级索引:
    • 覆盖索引:h2
    • 回表查询:h2+h1
  • 范围查询:这种情况相对比较复杂,但跟点查询的原理类似,读者可自行分析;
  • 全表查询:B+树的叶子结点是通过链表连接起来的,对于全表查询,需要从头到尾将所有的叶子结点访问一遍。

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亿条!

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

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

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

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

**怎样得到一张含有所有索引的Root页所在的位置的表呢?在《MySQL技术内幕:InnoDB存储引擎》书中分析过这个页(即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;

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

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

$hexdump -C -s 49216 -n 10 edu_comment.ibd
0000c040  00 01 00 00 00 00 00 00  00 9a                    |..........|
0000c04a

这里,49216表示的是163843+64,即从第3个页内偏移量64位置开始读取10个字节,前两个字节为PAGE_LEVEL,后8个字节是index_id,就是上图中看到的index_id=154(0x9a(十六进制) = 154(十进制))的主键索引,这里 PAGE_LEVEL为00 01*,那么索引树的高度就为2。

四、插入10w条数据查看索引的高度

delimiter;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=100000)do insert into guli.edu_comment (id, course_id, teacher_id, member_id, nickname, avatar, content, is_deleted, gmt_create, gmt_modified) values (i, '1192252213659774977', '1189389726308478977', '1', '小三123', 'ht', '课程很好', 0, '2019-11-13 14:16:08', 14:16:08'); set i="i+1;" end while; end;; delimiter; < code></=100000)do>

经过1分多钟的插入,edu_comment表中的数据已经达到了10w条,再次查看主键索引的高度。

$hexdump -C -s 49216 -n 10 edu_comment.ibd
0000c040  00 02 00 00 00 00 00 00  00 9a          |..........|
0000c04a

可以看到主键索引的高度来到了3层,由于服务器硬盘容量较小,插入了1900w条数据。主键索引在数据量达到3w左右会从2层高度上升到3层(辅助索引会在数据量为数万到数十万时上升到3层高度,因为仅含主键值和索引值,没有整行数据)。根据网上资料,数据量在2000w左右时,树的高度会达到4层,数据库性能下降较为明显,2000w分库分表的由来。

动手实验查看MySQL索引的B+树的高度
$hexdump -C -s 49216 -n 10 edu_comment.ibd
0000c040  00 03 00 00 00 00 00 00  00 9a                    |..........|
0000c04a

主键索引高度来到了4层,主键类型为char(19)。

索引高度h也跟索引字段的数据类型有关。如果是int或short,扇区多,索引效率更好,整个索引看起来属于”矮胖”型;而如果是varchar(32)等,那扇区少,整个索引看起来属于”瘦高”型,索引效率自然要低些。所以我们在字段选取类型时,其类型越简单效率越好。

分页查询效率:

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

参考资料:
[1]MySQL索引的B+树到底有多高?
https://mp.weixin.qq.com/s/VmgpA3fZlv0JxERYB2tt5g
[2]面试官:MYSQL单表数据达2000万性能严重下降,为什么?

https://mp.weixin.qq.com/s/7_Wv3wZX5sOxF17iSM436A
[3]一文搞懂MySQL索引页结构
http://www.cppcns.com/shujuku/mysql/463625.html
[4]再有人问你为什么MySQL用B+树做索引,就把这篇文章发给她
https://mp.weixin.qq.com/s/8nx4yLOg542p_fmqjKDrKw
[5] http://blog.codinglabs.org/articles/theory-of-mysql-index.html

Original: https://www.cnblogs.com/BetterCallSaul/p/MySQL.html
Author: 得失乐与悲与梦儿
Title: 动手实验查看MySQL索引的B+树的高度

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612616/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • [springmvc]springmvc的实现流程原理,以及快速创建一个三层架构项目

    1.回顾mvc 模型 模型(dao,service):业务逻辑,保存数据的状态 视图 视图(jsp,html……):展示页面 控制器 控制(servlet)…

    数据库 2023年6月16日
    064
  • ShardingSphere 异构迁移最佳实践:将3.5亿量级的顾客系统 RTO 减少60倍

    Apache ShardingSphere 助力当当 3.5 亿用户量级顾客系统重构,由 PHP+SQL Server 技术栈无缝转型为 Java+ShardingSphere+M…

    数据库 2023年5月24日
    075
  • 网卡限速工具之WonderShaper

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 什么是WonderShaper …

    数据库 2023年5月24日
    081
  • Elasticsearch搜索引擎的使用

    当用户在搜索框输入关键字后,我们要为用户提供相关的搜索结果。 这种需求依赖数据库的模糊查询like关键字可以实现,但是like关键字的效率极低,而且查询需要在多个字段中进行,使用l…

    数据库 2023年6月14日
    0126
  • Nginx 代理超时

    Nginx代理超时 内部测试并未出现问题 但是再客户那边出现了 BUG System.InvalidOperationException: Response Content-Len…

    数据库 2023年6月11日
    065
  • python 里 certifi 库的作用

    安装了certifi之后,和requests库一样也有一个cacert.pem,可以用编辑器打开cacert.pem,里面包含了很多可信任知名公司的证书/公钥库的路径,我这里是py…

    数据库 2023年6月9日
    087
  • 浅谈多线程中数据的绑定和赋值

    我们知道,微软的.NET控件做了大量的工作,用起来还是不错的,一般的数据绑定或者赋值比较简单。如下所示 文本赋值: txtTest.Text = “abc”…

    数据库 2023年6月11日
    060
  • MySQL 的 GRANT和REVOKE 命令

    MySQL 的 GRANT和REVOKE 命令 GRANT – 授权 将指定 &#x64CD;&#x4F5C;&#x5BF9;&#x8C…

    数据库 2023年5月24日
    0117
  • mysql语法使用详细代码版

    mysql 1.什么是数据库 数据库:(DB,DataBase)作用:用来存储数据,管理数据。Txt,Excel,word是在数据库出现之前存储数据的。概念:数据仓库,安装在操作系…

    数据库 2023年5月24日
    067
  • Java实现平滑加权轮询算法–降权和提权

    上一篇讲了普通轮询、加权轮询的两种实现方式,重点讲了平滑加权轮询算法,并在文末留下了悬念: 节点出现分配失败时降低有效权重值;成功时提高有效权重值(但不能大于weight值)。 本…

    数据库 2023年6月6日
    082
  • 8 int和Integer的区别

    数据类型 int是基本数据类型,Integer是int的包装类,属于引用类型 初始值 int的初始值为0,Integer的初始值为null 存储位置 int是直接存储在栈中的,In…

    数据库 2023年6月6日
    086
  • Java面试题(四)–RabbitMQ

    1、MQ有哪些使用场景?(高频) 异步处理:用户注册后,发送注册邮件和注册短信。用户注册完成后,提交任务到 MQ,发送模块并行获取 MQ 中的任务。 系统解耦:比如用注册完成,再加…

    数据库 2023年6月16日
    068
  • firewall 命令简单操作

    Firewalld 是维护防火墙策略的守护程序的名称。使用 firewall-cmd 命令与防火墙配置进行交互, 使用区域概念对与系统交互的流量进行分段。网络接口分配给一个或多个区…

    数据库 2023年6月14日
    071
  • permgen space解决方案

    原文地址:http://outofmemory.cn/c/java-outOfMemoryError java.lang.OutOfMemoryError这个错误我相信大部分开发人…

    数据库 2023年6月11日
    077
  • 15. 三数之和

    给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。 注意:答案…

    数据库 2023年6月16日
    058
  • 工作中常用Less知识点实践总结

    工作中常用Less知识点实践总结,帮助你更好的使用Less 我所理解的Less的一些好处 函数式编程css 自定义变量用于整体主题调整 嵌套语法简化开发复杂度 mixin的写法 ….

    数据库 2023年6月11日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球