索引的本质
索引是帮助MySQL高效获取数据的排好序的数据结构
索引的数据结构
- 二叉树
- 红黑树
- Hash表
- B-Tree
select * from t where t.col2=42
我们可以想一下,如果这张表不加任何索引的化,mysql底层肯定是逐行去查找
这里面没查找一行记录实际上是对磁盘做交互,mysql数据表都是存储在磁盘上的,查找一次都是一次IO,这样效率是非常低,查找的特别慢
我们来看一下利用二叉树去查找
先查找父节点是32,不等于42,因为二叉树的特性右边子节点肯定大于父节点,左边子节点肯定小于父节点,可以看到父节点32<42,那肯定往右边子节点查找,42=42找到了
如果使用利用二叉树去查找id,因为id默认递增的,所有我们可以看一下,二叉树排列一直在右边,这样就退化成链表了,查询的时候还是一个一个的查询,没有任何优化,证明这个是有问题的
不懂二叉树的可以访问这个网站研究一下二叉树
www.cs.usfca.edu/~galles/vis…
我们来看一下二叉树
红黑树其实也叫二叉树,全名叫二叉平衡树,它可以自我平衡,这样会让它的高度减少很多,可以提高查询效率
不知道红黑树的可以访问这个网站研究一下红黑树
为什么mysql底层没有使用红黑树,因为如果数据库一张表有500万条记录,把唯一索引放到这里面去,假设500万个索引红黑树的高度是20,如果要查找的数据在红黑树的叶子节点也就是最底层,需要进行20次查询,也就是要经过20次磁盘IO,这样遇到数据量比较大的场景,红黑树也是不适用的
B-Tree
- 叶节点具有相同的深度,叶节点的指针为空
- 所有的索引元素不重复
- 节点上的数据从左到右递增排列
B-Tree全称又叫多叉平衡树
B+Tree
B+Tree 和B-tree区别
- B+Tree把data放到了叶子节点上
- 叶子节点二二之间有个指针
查询过程:
查询col=30 先把父节点load内存里,然后快速定位查找,发现在15-46之间,然后把15-46之间这个位置对应的节点load到内存里,然后快速定位查找,发现30在20-49之间,然后把20-49之间这个位置对应的节点load到内存里,然后把20-30load到内存中随机查找,然后查找到30这个节点然后把30索引的data取出来,就找到了30索引所在行的数据
InnoDB
为什么InnoDB表必须有主键,并且推荐使用整型的自增主键?
会有人产生质疑,我以前用InnoDB引擎设计表没有设置主键怎么还可以,因为如果没有设置主键,mysql自己会在你设计的表结构上匹配到一个字段设为主键,如果没有匹配到mysql会新增一个字段设置为主键只是是隐形的看不到
为什么推荐整型,因为把索引放到B+Tree会把节点放到内存中比较,很明显整型的比较比字符串效率高很多
Hash表
为什么Hash索引很少使用
不可因为hash算法让Hash表建立索引确实很快,有的可能会说可能会导致hash碰撞,但是在mysql底层已经对hash进行了优化处理,很少会发生hash碰撞,我们在范围查找的时候,如果执行selelct * from t where t.col2 > 89
因为col2数据不是按照顺序,在mysql底层还是一个一个的比较,这和没有添加索引一样的效果,不能优化查询效率,所以很少使用Hash索引
为什么推荐使用自增主键
我们来不使用递增用uuid,我们插入8再插入7看一下是什么效果,我们可以想象一下插入8肯定在6的右边
我们再来插入7,mysql要求在维护索引结构的时候从左到右依次递增,我们可以想象一下,肯定在6-8之间,但是这个节点最多只能放三个元素,再放一个,我们可以看一下原来的大节点分裂成两个小结点,而且还把雍余的索引往上提了,说白了树有个平衡的过程
那么我们就知道为什么建议使用自增主键了,因为如果使用自增主键,加元素只会一直在节点右边添加,但是使用不是递增的uuid,比如我现在新加一行记录,安装从左到右递增,应该维护在5-8那个节点,但是这个节点满了,非要往那里面叉就会导致分裂成两个节点,然后这个树还要在某个局部的位置做一个平衡索引的上移,不言而喻,是自增主键每次往后面插入不会导致树分裂效率高还是时不时还要导致树分裂还要做一下平衡哪个效率高,肯定是自增主键的效率高
联合索引
最左前缀原则
如果我们跳过第一个索引name直接在B+Tree树里面来查找大小,我们正常情况是B+Tree树从左到右依次递增排好序的,我可以比大小从根节点快速定位,比如a=1001,我可以快速定位到name索引1001的那三个记录,发现下一个记录是1003我肯定不会去走了,因为从左到右依次递增,我可以快速定位这几个地方,我只要快速扫描这几个索引就行了,后面的索引就不需要去扫描了,但是我们现在看第二个字段,我们会发现,第二个字段也是排好序的,但是前提是它排好序的字段前提是第一个字段相等的前提下,我们跳过第一个字段,单纯来看第二个字段,我看整张表的所有字段,它可能就不是排好序的,可能下个节点也会出现Assistant,但是它的第一个字段可能就是1005了,单纯看第二个在整张表来说就不是排好序的,比如b=Assistant,可能说在1001节点找到了Assistant不用扫描记录了,确实在1001节点后两个元素不需要扫描记录了,但是后面的节点肯会出现A开头的字段,所以不能不往下扫描,那就意味着你对这所有的索引元素全部扫描,那这个索引就用不到,但是如果能走索引的话,按照B+Tree树从左到右依次递增的规律找到1001节点的就完事了,不需要往下找了
以上就是针对于的mysql底层的一些理解