深入理解Mysql索引底层数据结构与算法

索引

索引是帮助MySQL高效获取数据的排好序数据结构(容易忽略的点:排好序)(形象点就是教科书的目录)

索引存储在文件里(也就是说有IO操作)

索引结构:

这里说说在几种数据结构中,mysql为什么选择hash,B+Tree

  1. 二叉树
  2. 红黑树
  3. hash
  4. BTree

首先,如果数据没有索引,那么我们读取数据是这样的

这里有一篇很好的硬盘存取原理文章,看完更容易理解: https://www.cnblogs.com/leezhxing/p/4420988.html 

上面我们发现读取数据特别耗时,那有没有比较节时的数据结构,我们可以看看二叉树 

 上面虽然优化了,但是mysql为什么选择 B+Tree

这里介绍一个动态演示数据结构的网址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

二叉树与红黑树的比较

从上面我们发现,红黑树相比较于二叉树又进步了一些,但红黑树还是有些问题:那就是数据量大的话,红黑树的深度会很深,也就是说深度不可控,这样一来查找数据还是会很耗时

HASH

从上面我们发现,相比较于红黑树,hash可以固定“深度”,且映射到磁盘存储引用,这样查找数据直接告诉磁盘数据在哪,查找数据也挺快的,但是 hash 还是有些不足:那就是不能范围查找,比如我们查找Col1>1的数据,当然如果我们查询操作很少的话,我们也可以选择hash数据结构,因为它查找数据挺快的,这也是mysql的索引方法除了B+Tree还有hash

BTree

 从上面看,我们发现BTree又进步了一些,查询速度提高,存储容量也没影响到。当然有人可能会这样想,那我们为什么不把数据全部都存在一个节点,这样深度不就是1了吗?

当然不行了!java拿取数据一般是这样的:java程序-->CPU--->内存---->硬盘,而内存与硬盘的交互是有大小限制的,是一页数据4k左右,所以不能把所有数据都放在一个节点来获取,一般来说节点会尽量预存4K容量。

看到这里,我们知道(4K=节点;节点=小节点*小节点的容量)一个节点是4K,而节点内有几个小节点,那么也就是说,只要我们每个的小节点的data容量越小,那么可以存的节点也就可以更多。

B+Tree

B+Tree通过把data不放在非叶子节点来增加度(小节点),一般会一百个以上使得深度是3~5,从而减少查询次数。并且,叶子节点之间会有指针,数据又是递增的,这使得我们范围查找可以通过指针连接查找,而不再从上面节点往下一个个找。

结论:B+Tree 既减少查询次数又提供了很好的范围查询

 MyISAM索引实现(非聚集)

  MyISAM索引文件和数据文件是分离的,文章一开始也介绍了,数据.MYD+结构.frm+索引.MYI三个文件

 那myisam的索引是什么样的?

InnoDB索引实现(聚集)

  • 数据文件本身就是索引文件
  • 表数据文件本身就是按B+Tree组织的一个索引结构文件
  • 聚集索引-叶节点包含了完整的数据记录
  • 为什么InnoDB表必须有主键,并且推荐使用整型的自增主键?
  • 为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

上面的问题对应字体颜色说明 (可能说的有些乱,可以参考这个的描述:https://baijiahao.baidu.com/s?id=1567647881305129&wfr=spider&for=pc) 

联合索引的底层存储结构

练习题

在employee表建联合索引 (emp_no,title,from_date)

分析以下几条sql的索引使用情况

SELECT * from employee where emp_no = '10001' and title = 'xxx' and from_date = '2018-10-01 11:29:51'

SELECT * from employee where title = 'sss'

SELECT * from employee where emp_no > '10003'
 
SELECT * from employee where emp_no > '10003' and title = 'eeee'

SELECT * from employee where emp_no > '10003' ORDER BY title

#自己可以根据联合索引的数据结构猜猜看

也可以用explain来查看

猜你喜欢

转载自blog.csdn.net/caijunsen/article/details/83045985