目录
1、什么是索引
2、索引分类
3、索引的基本操作
3.1、主键索引
3.2、单列索引
3.3、唯一索引
3.4、复合索引
4、索引的底层原理
为什么使用B+Tree而不是B-Tree?
如果数据量特别大的情况下,B+Tree会不会深度太深影响查询效率?
5、聚簇索引和非聚簇索引
5.1、概念:
5.2、使用聚簇索引的优势
5.3、聚簇索引需要注意什么
5.4、为什么通常建议使用自增id
6、索引失效的常见场景
1.1、索引定义
索引是一种帮助MySQL提高查询效率的数据结构
1.2、索引的优点
加快数据查询的速度
1.3、索引的缺点
建表,把id设置为主键:
查看索引:
可以看到,我们没有设置索引,但数据库已经自动帮我们把主键设置为索引了~
建表,把age设置为单列索引:
通过上述,我们可以观察到,主键被数据库自动设置为索引,单列索引可以和主键索引同时存在~
建表,把name设置为唯一索引:
唯一索引和主键索引的区别:
主键索引的值不能为空,而唯一索引的值可以为空(我在MySQL5.7版本上是支持多个数据为空的的)~
建表,把name和age设置为复合索引:
复合索引底层如何存储的,我们先来看看索引的底层原理:
在MySQL中,实际存储数据,是如何存储的呢?
如下:
看上图,我们会知道存储数据时,是按照三部分存储的,一个是主键索引,一个是数据部分,一个是指针。那么指针指向哪里呢?指针是指向下一个节点的:
数据就是这样组织起来的。有一个点需要注意的是,MySQL索引底层的数据是按照主键进行有序放置的,也就是说,数据是按照主键索引进行有序存储的。那么问题来了,当我们存入的数据特多时,我们是需要把数据全部遍历一遍吗?这样的话,时间复杂度是不是有点太大了,如果有一万个数据,运气不好的话,找数据不是得找一万次?
那根据我们上述所说的数据是按照主键有序存储的,那我们就可以对底层数据存储进行优化,把数据划分成一个个的区域,例如下面的3个数据一划分:
划分后,我们就可以把每个区域看成是一页页的数据(MySQL中,每一页默认是规定存储16KB的数据),我们就可以给每一页数据一个目录,如下:
观察上图,我们就可以得知,目录中的数据其实就是每一页的数据的第一个数据~
细心的小伙伴会发现,目录中存储的数据,并不是完整的数据,而是只存放了一个数据的主键和指针~
如果说,如果数据量非常非常大,目录这个区域也已经超过了16KB的数据怎么办,是不是需要我们再给目录再提一层目录呢~如下:
此时,看到这里学习过数据结构的小伙伴就会知道,这个不就是B+树吗?对的,MySQL索引就是采用了B+的数据结构。
B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎(Mysql的默认引擎就是InnoDB)就是用B+Tree实现其索引结构。
为什么使用B+Tree而不是B-Tree?
如果数据量特别大的情况下,B+Tree会不会深度太深影响查询效率?
不会哦~B+Tree的高度一般都是在2~4层,而MySQL的InnoDB存储引擎在设计时,是将根节点常驻内存的,也就是说,查找某一键值的行记录时最多只需要1~3次磁盘I/O操作~
为什么B+Tree的高度一般都是在2~4层?
我们可以来算一算一页能存放多少数据:
假设是我们刚才的数据的表,有一个id,一个name,一个age。id是int类型,4个字节(数据量大时,需要使用bigInt,8个字节);name假设是设置20字节;age为int类型,4个字节;一个指针,8个字节;一共一条数据36字节。
1KB=1024字节;一页可以存16KB,16*1024/28约等于455条数据。
当我们的B+Tree的高度为2时,也就是说有一层目录,我们来算算能存多少数据:
目录中,只存放id和指针,一共12个字节,一页能存放数据个数:16*1024/12约等于1365个数据。那么1365的数据就对应1365页叶子节点的数据,约等于对应621226条数据。
当B+Tree的高度为3时,大家可以自己算算,能存的数据量其实是非常大的,因此一般B+Tree的高度都是在2~4层的~
聚簇索引:
也就是说,数据库中的所有数据都是放在聚簇索引的叶子结点中的,而其他索引都属于辅助索引(例如:复合索引、前缀索引、唯一索引等),辅助索引叶子结点中存储的不是数据的物理位置,而是主键值,因此,辅助索引访问数据时总是需要二次查找的:
说明:
非聚簇索引:
MYISAM就是使用的非聚簇索引,非聚簇索引的两颗B+树看上去没有什么不同,节点的结构完全一致,只是存储的内容不同。主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子结点都使用一个地址指向真正的表数据,对于表数据来说,这两个建没有任何差别,由于索引树是独立的,通过辅助建索引无需访问主键的索引树:
每次使用辅助索引检索都要经过两次B+树查找,看上去聚簇索引的效率明显要低于非聚簇索引,这不是多此一举吗?聚簇索引的优势在哪?
当使用主键为聚簇索引时,主键最好不要使用UUID,因为UUID的值太过于离散,不适合排序且可能出现新增记录的UUID,会插入在索引树中间的位置,导致索引树调整复杂度变大,消耗更多的时间和资源。
建议使用int类型的自增,方便排序并且默认会在索引树的末尾增加主键值,对索引树的结构影响最小。而且,逐渐值占用的存储空间越大,辅助索引中保存的主键值也会跟着变大,占用存储空间,也会影响到IO操作读取到的数据量~
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻的存放在磁盘上的。如果主键不是自增id,那么可以想象,例如使用UUID,每次都是随机值,就会导致每次添加数据时,都不要不断地调整数据的物理地址、重新分页等。当然也有其他措施来减少这些操作,但是这是无法减少这些操作的,但却无法彻底避免。那如果说使用自增,那就简单了,他只需要一页一页的写,索引结构相对紧凑,磁盘碎片少,效率也高~
好啦,本期就到这里咯,下期见~~~