前言
- 众所周知,索引在数据库中是非常重要的存在。我上大学那会,网购刚刚开始流行,每当双十一过后,学校快递站摆满了大量的快递,体积、重量、形状各不相同。由于没有经验,一开始快递都是这样放的:
- 我们是怎么找的呢。。。一个一个翻呗。运气好,第一个就拿到了,食堂加个鸡腿庆祝一下;运气不好呢~~~
- 后来快递站改进了,把不同的快递分类。顺丰的放一堆,韵达的放一堆。。。这样就快很多嘛!
- 再后来,在快递分类的基础上,衍生出了几种进一步的摆放方法:有按编号排序的,有按条形码后四位排序的。。。等等等等。
- 上面这种通过设置查找节点来加快查找速度的方式,其实就是mysql中索引的作用。用一句话形容,索引是帮助mysql高效获取数据的排好序的数据结构。
- 索引的数据结构一般有二叉树、红黑树、B树、Hash表。
索引的数据结构
二叉树
- 简单来讲,二叉树就是先有一个根节点,然后往下长分枝,小的在左边,大的在右边:
- 在这个结构中,如果要找9这个数据,那么就是8->10->9,3次。但是如果在下面这个结构中呢:
- 这也是二叉树,但是找到9需要9次。
红黑树
- 红黑树是一种自平衡二叉树,当依次插入1,2,3,4,5,6,7,8,9时,
- 这时候找到9,需要4次。
小结
从上面3个图可以看出来,查找的效率,其实是和树的高度是紧密相连的。查找目标所在的高度越大,查找时的效率也就越低。下面继续看B树是怎么样的。
B树
B树分为B-Tree和B+Tree,B-Tree是多路搜索树,B+Tree是B-Tree的变种,有着比B-Tree更高的查询性能。
B-Tree
结构图:
带数据:
- 可以看到B-Tree的特点:
- 叶节点具有相同的深度
- 所有索引元素不重复
- 节点中的数据索引从左到右递增
- 同样的,查找效率和树的高度也是负相关。而且,如果让每个叶节点尽可能的多放索引,在数据量很大的时候,提高的效率就很可观了。但是问题来了,由于每一个索引中都带有数据,数据占用的空间势必影响这个叶节点能放的索引数量。而且各叶子节点不连续。
B+Tree
结构图:
带数据:
- 可以看到B+Tree的特点:
- 非叶子节点不存储data,只存储冗余索引,这样可以放更多的节点
- 叶子节点包含了所有的索引字段
- 叶子节点之间有指针相连,提高了区间访问时的速度
- 因为叶节点是放在内存中的,叶子节点是放在硬盘中的,所以查询数据的速度很大程度上是取决于索引的查询速度。
- 看到这有同学会问,那我把所有数据都放在叶节点,查询效率岂不更快?比如这样:
- 问题是如果都放内存,在面对大量表和大量数据时,内存会被占满,查询效率也会随之下降。那么放多少才是合适的呢,Mysql设置叶节点大小为16KB。总共能放约2千万的数据(叶子节点数据按1KB算)。
- 并且,树高度为3!!那如果换算成B-Tree时,高度为N,2千万数据=16的N次方,很明显N远大于3。
Mysql存储引擎
MyISAM
存储方式:
- MyISAM的索引文件和数据文件是分离的,也叫非聚集。
- 当我们用sql语句select * from table where id=25时,找到的data是改行数据在磁盘中的地址0x06。
InnoDB
存储方式:
- InnoDB索引叶子节点包含了完成的数据
- 表数据文件本身就是B+Tree结构
- 在设计数据库时强烈建议建主键,而且是整型的自增主键(自增保证数据在插入时,不用分裂节点)。这样可以充分利用B+Tree索引递增、叶子节点之间连续的特性,提高查询效率。作为对比,如果使用uuid(au7812ndf.....),不仅空间占用量大,查询时也没有整型快捷。
- 非主键索引的结构(二级索引....)
![]()
- 非主键索引叶子节点存储的是主键值(节省空间),当通过二级主键查找时,会先找到对应的主键,再通过主键查找——回表(一致性,插入数据时,不用2边都插入)。
联合索引
- 联合索引也是B+Tree,根据最左前列原理排序
'user_name','age','country' USING BTREE
1. select * from table where user_name='Allen' and age=20
2. select * from table where age=20 and country='china'
3. select * from table where country='china'
4. select * from table where user_name='Allen' and country='china'
- 这4个sql语句,只有1的联合索引会起作用。2和3不起作用,因为叶节点上索引在已知条件下不是有序排列的。4只有user_name这一索引会起作用,因为country索引在age不确定的情况下,不是有序的。
总结
看到这里,是不是对自己写的sql语句有了新的认识