深入理解MySQL索引之B+Tree
正确的创建合适的索引,是提升数据库查询性能的基础。在正式讲解之前,对后面举例中使用的表结构先简单看一下:
1 索引是什么及工作机制?
索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构。其工作机制如下图:
上图中,如果现在有一条sql语句 select * from user where id = 40
,如果没有索引的条件下,我们要找到这条记录,我们就需要在数据中进行全表扫描,匹配id = 13的数据。
如果有了索引,我们就可以通过索引进行快速查找,如上图中,可以先在索引中通过id = 40进行二分查找,再根据定位到的地址取出对应的行数据。
2. MySQL数据库为什么要使用B+TREE作为索引的数据结构?
- 二叉树:线性链表相当于全表扫描
- 平衡二叉树:树的深度造成IO问题、一页/一个节点内容少空间浪费
- 多路平衡二叉树:B+Tree扫库和扫表能力更强,B+TREE只需要遍历他的所有叶子节点即可(叶子节点之间有引用)
B+TREE磁盘读写能力更强。因为保存更多的关键字和数据,所以B+TREE读写一次磁盘加载的关键字比B TREE更多
B+Tree排序能力更强
B+Tree查询性能稳定
2.1 二叉树为什么不可行
对数据的加速检索,首先想到的就是二叉树,二叉树的查找时间复杂度可以达到O(log2(n))。下面看一下二叉树的存储结构:
如果我们要查询的数据为4,则需要遍历所有的节点才能找到4,即,相当于全表扫描,就是由于存在这种问题,所以二叉查找树不适合用于作为索引的数据结构。
2.2 平衡二叉树为什么不可行
如果上图中平衡二叉树保存的是id索引,现在要查找id = 8的数据,过程如下:
到这里,平衡二叉树解决了存在线性链表的问题,数据查询的效率好像也还可以,基本能达到O(log2(n)), 那为什么mysql不选择平衡二叉树作为索引存储结构,他又存在什么样的问题呢?
- 搜索效率不足。一般来说,在树结构中,数据所处的深度,决定了搜索时的IO次数(MySql中将每个节点大小设置为一页大小,一次IO读取一页 / 一个节点)。如上图中搜索id = 8的数据,需要进行3次IO。当数据量到达几百万的时候,树的高度就会很恐怖。
- 查询不不稳定。如果查询的数据落在根节点,只需要一次IO,如果是叶子节点或者是支节点,会需要多次IO才可以。
- 存储的数据内容太少。没有很好利用操作系统和磁盘数据交换特性,也没有利用好磁盘IO的预读能力。因为操作系统和磁盘之间一次数据交换是以页为单位的,一页大小为 4K,即每次IO操作系统会将4K数据加载进内存。但是,在二叉树每个节点的结构只保存一个关键字,一个数据区,两个子节点的引用,并不能够填满4K的内容。幸幸苦苦做了一次的IO操作,却只加载了一个关键字。在树的高度很高,恰好又搜索的关键字位于叶子节点或者支节点的时候,取一个关键字要做很多次的IO。
那有没有一种结构能够解决二叉树的这种问题呢?有,那就是多路平衡查找树。
2.3 多路平衡查找树(Balance Tree)
假设要从上图中查找id = X的数据,B TREE 搜索过程如下:
- 取出根磁盘块,加载40和60两个关键字。
- 如果X等于40,则命中;如果X小于40走P1;如果40 < X < 60走P2;如果X = 60,则命中;如果X > 60走P3。
- 根据以上规则命中后,接下来加载对应的数据, 数据区中存储的是具体的数据或者是指向数据的指针。
B树确实已经很好的解决了问题,我先这里先继续看一下B+Tree结构,再来讨论BTree和B+Tree的区别。
- 取出根磁盘块,加载1,28,66三个关键字。
- X <= 1 走P1,取出磁盘块,加载1,10,20三个关键字。
- X <= 1 走P1,取出磁盘块,加载1,8,9三个关键字。
- 已经到达叶子节点,命中1,接下来加载对应的数据,图中数据区中存储的是具体的数据。
2.4 B TREE和B+TREE区别是什么?
B+Tree 关键字的搜索采用的是左闭合区间,之所以采用左闭合区间是因为他要最好的去支持自增id,这也是mysql的设计初衷。即,如果id = 1命中,会继续往下查找,直到找到叶子节点中的1。
B+Tree 根节点和支节点没有数据区,关键字对应的数据只保存在叶子节点中。即只有叶子节点中的关键字数据区才会保存真正的数据内容或者是内容的地址。而在B树种,如果根节点命中,则会直接返回数据。
在B+Tree中,叶子节点不会去保存子节点的引用。
B+Tree叶子节点是顺序排列的,并且相邻的节点具有顺序引用的关系,如上图中叶子节点之间有指针相连接。
2.5 MySQL为什么最终要去选择B+Tree?
B+Tree是B TREE的变种,B TREE能解决的问题,B+TREE也能够解决(降低树的高度,增大节点存储数据量)
B+Tree扫库和扫表能力更强。如果我们要根据索引去进行数据表的扫描,对B TREE进行扫描,需要把整棵树遍历一遍,而B+TREE只需要遍历他的所有叶子节点即可(叶子节点之间有引用)。
B+TREE磁盘读写能力更强。他的根节点和支节点不保存数据区,所以根节点和支节点同样大小的情况下,保存的关键字要比B TREE要多。而叶子节点不保存子节点引用,能用于保存更多的关键字和数据。所以,B+TREE读写一次磁盘加载的关键字比B TREE更多。
B+Tree排序能力更强。上面的图中可以看出,B+Tree天然具有排序功能。
B+Tree查询性能稳定。B+Tree数据只保存在叶子节点,每次查询数据,查询IO次数一定是稳定的。当然这个每个人的理解都不同,因为在B TREE如果根节点命中直接返回,确实效率更高。
3 MySQL B+Tree具体落地形式
这里主要讲解的是MySQL根据B+Tree索引结构不同的两种存储引擎(MYISAM 和 INNODB)的实现。
首先找到MySQL保存数据的文件夹,看看MySQL是如何保存数据的:
mysql> show variables like '%datadir%';
+---------------+------------------------+
| Variable_name | Value |
+---------------+------------------------+
| datadir | /usr/local/mysql/data/ |
+---------------+------------------------+
入到这个目录下,这个目录下保存的是所有数据库,再进入到具体的一个数据库目录下。就能够看到MySQL存储数据和索引的文件了。
这里我创建了两张表,user_innod和user_myisam,分别指定索引为innodb和myisam。对于每张表,MySQL会创建相应的文件保存数据和索引,具体如下:从图中可以看出:
MYISAM存储引擎存储数据库数据,一共有三个文件:
Frm:表的定义文件。
MYD:数据文件,所有的数据保存在这个文件中。
MYI:索引文件。Innodb存储引擎存储数据库数据,一共有两个文件(没有专门保存数据的文件):
Frm文件: 表的定义文件。
Ibd文件:数据和索引存储文件。数据以主键进行聚集存储,把真正的数据保存在叶子节点中。
3.1 MyISAM存储引擎
说明:为了画图简便,下面部分图使用在线数据结构工具进行组织数据,组织的B+Tree为右闭合区间,但不影响理解存储引擎数据存储结构。
如果有多个索引,表现形式如下:
所以在MYISAM存储引擎中,主键索引和辅助索引是同级别的,没有主次之分。
3.2 Innodb存储引擎
Innodb主键索引为聚集索引,首先简单理解一下聚集索引的概念:数据库表行中数据的物理顺序和键值的逻辑顺序相同。
Innodb以主键索引来聚集组织数据的存储,下面看看Innodb是如何组织数据的。
如上图,主键索引的叶子节点保存的是真正的数据。而辅助索引叶子节点的数据区保存的是主键索引关键字的值。
之所以这样设计,一个原因就是:如果和MyISAM一样在主键索引和辅助索引的叶子节点中都存放数据行指针,一旦数据发生迁移,则需要去重新组织维护所有的索引。
把Innodb 和 MYISAM区别放在一张图中看,就如下所示:
4 创建索引的几大原则
4.1 列的离散型
离散型的计算公式:count(distinct column_name):count(*)
,就是用去重后的列值个数比个数。值在 (0,1] 范围内。离散型越高,选择型越好。
如下表中各个字段,明显能看出Id的选择性比gender更高。
mysql> select * from user;
+----+--------------+------+--------+
| id | name | age | gender |
+----+--------------+------+--------+
| 20 | 君莫笑 | 15 | 1 |
| 40 | 苏沐橙 | 12 | 0 |
| 50 | 张楚岚 | 25 | 1 |
| 60 | 诸葛青 | 27 | 1 |
| 61 | 若有人兮 | 38 | 0 |
| 64 | 冯宝宝 | 18 | 0 |
+----+--------------+------+--------+
什么说离散型越高,选择型越好?
因为离散度越高,通过索引最终确定的范围越小,最终扫面的行数也就越少。
4.2 最左匹配原则
4.3 最少空间原则
前面已经说过,当关键字占用的空间越小,则每个节点保存的关键字个数就越多,每次加载进内存的关键字个数就越多,检索效率就越高。创建索引的关键字要尽可能占用空间小。
5 联合索引
单列索引:节点中的关键字[name]
联合索引:节点中的关键字[name, age]
可以把单列索引看成特殊的联合索引,联合索引的比较也是根据最左匹配原则。
5.1 联合索引列的选择原则
5.2 实例分析
6. 覆盖索引
当然,如果你同时需要获取age的值:
select id,age from users where name = ?
这样就无法使用到覆盖索引了。
7 总结
索引列的数据长度满足业务的情况下能少则少。
表中的索引并不是越多越好,冗余或者无用索引会占用磁盘空间并且会影响增删改的效率。
Where 条件中,like 9%, like %9%, like%9,三种方式都用不到索引。后两种方式对于索引是无效的。第一种9%是不确定的,决定于列的离散型,结论上讲可以用到,如果发现离散情况特别差的情况下,查询优化器觉得走索引查询性能更差,还不如全表扫描。
Where条件中IN可以使用索引, NOT IN 无法使用索引。
多用指定查询,只返回自己想要的列,少用select *。
查询条件中使用函数,索引将会失效,这和列的离散性有关,一旦使用到函数,函数具有不确定性。
联合索引中,如果不是按照索引最左列开始查找,无法使用索引。
对联合索引精确匹配最左前列并范围匹配另一列,可以使用到索引。
联合索引中,如果查询有某个列的范围查询,其右边所有的列都无法使用索引。
8 扩展
mysql一张表到底能存多少数据呢?如下图
关于分页:内存一页大小4KB。MySQL数据页大小是16KB。(确切的说是InnoDB数据页大小16KB)
以上1-7章转自https://blog.csdn.net/b_x_p/article/details/86434387
深入理解MySQL索引之B+Tree相关推荐
- SQL - 深入理解MySQL索引之B+Tree
正确的创建合适的索引,是提升数据库查询性能的基础.在正式讲解之前,对后面举例中使用的表结构先简单看一下: create table user (id bigint not null comment ' ...
- 深入理解MySQL索引之B+Tree(转载)
正确的创建合适的索引,是提升数据库查询性能的基础.在正式讲解之前,对后面举例中使用的表结构先简单看一下: create table user ( id bigint not null ...
- mysql索引_mysql系列:深入理解mysql 索引特性(屡试不爽的mysql索引总结)
原标题:mysql系列:深入理解mysql 索引特性(屡试不爽的mysql索引总结) mysql为什么使用B+ Tree索引,不使用B- Tree索引? 索引顺序如何生效? 什么是覆盖索引? orde ...
- 深入理解MYSQL索引优化:多列索引
索引是什么 是存储引擎用于找到数据的一种数据结构. C/C++ Linux服务器开发高级架构视频点击:C/C++Linux服务器开发高级架构师/Linux后台架构师-学习视频 MYSQL索引优化视频详 ...
- 深入理解MySQL索引和优化丨MySQL的核心原理
索引介绍 文章相关视频讲解: C/C++ Linux服务器开发高级架构学习视频点击:C/C++Linux服务器开发/Linux后台架构师-学习视频 理解mysql-索引及其优化 MySQL的核心原理分 ...
- 理解MySQL——索引与优化篇
写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将 ...
- mysql索引数据结构图解_深入理解Mysql索引底层数据结构与算法
索引的定义:索引(Index)是帮助MySQL高效获取数据的数据结构. Q1:大家使用索引有没有想过这个问题?为什么索引能够帮助mysql高效获取数据?我一一给大家道来!在给大家讲之前,先更大家分享一 ...
- MySQL索引和B+Tree底层原理
目录 说明 一.索引的引入 二.MySQL为什么使用B+树,而不是使用B树,AVL? 二叉搜索树 AVL 平衡二叉搜索树 B-Tree(B树) B+Tree(B+树) B+Tree衍生问题 三.什么是 ...
- 腾讯三面灵魂问题:如何理解MySQL索引底层数据结构
MySQL 索引相关的数据结构有两种,一种是 B+tree,一种是 Hash,那么为什么在 99.99% 很多情况下都使用的是 B+tree索引呢? 索引的底层数据结构是怎样的呢? 接下来就听小二娓娓 ...
最新文章
- 【老孙随笔】关羽和吕蒙——天才的失败
- bluez 设置绑定pin码_国家工信部重要提醒:一定要设置这个密码!
- python爬取本地天气信息_用Python写一个爬取中国天气网的终端版天气预报爬虫
- C++(2)--代码结构
- vue 仿二手交易app_Vue项目开发-仿蘑菇街电商APP
- php workerman定时任务
- 嵌套组合图echarts
- [转载] 信息系统项目管理师教程——06 信息化基础知识
- mysql FROM_UNIXTIME 格式化MYSQL时间戳函数
- java即时通讯聊天工具
- adb发送什么命令能在手机屏幕弹窗显示_如何通过命令给手机刷机
- c语言实验--九九乘法表,C语言实验报告(四)
- matlab张正友程序,张正友标定程序—MATLAB
- 【爬虫实战】自制属于你自己的在线翻译程序 - 爬取 360 在线翻译(教学 + 实践)
- Latex/CSDN字母输入对照表
- 爬虫取中间文本_【实战No.2】1小时打造你自己的网络爬虫
- 华中科技大学计算机网络教材,华中科技大学计算机网络复习资料.ppt
- 5年来做QQ与QQ群营销所走过的坑、奉劝大家别再在这块上花心思了
- 如何批量重命名多张图片
- R语言和医学统计学(5):多因素方差分析