数据库的索引类型
参考资料:MySQL实战45讲
普通索引
- 普通索引允许索引内容有重复数据,任务是为了加快对数据的访问速度。没什么特别的要求,只要它是查询的条件,就可以给它加上普通索引
唯一索引
- 唯一索引相对于普通索引就有了一个条件,那就是索引列的值不可以重复,但是可以为空。很显然,拿个人信息库来举例的话,身份证号很合适,或者创建时给予的序号或工号、学号这种不会重复的值。想年龄、性别就不可以,名字也会有重名的(张伟震怒)。
- 所以唯一索引在插入时就需要先检查该索引数据是否在数据库中已经有了,在进行添加。
主键索引
- 主键索引和唯一索引很像,唯一的区别就是主键的关键字是PRIMARY,不同于唯一的UNIQUE。
组合索引
-
组合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合。
-
索引项是按照索引定义里面出现的字段顺序排序的,遵循最左前缀原则。
-
最左匹配原则
- 就是如果你的SQL语句用到了索引最左边的字段或者字符,就可以利用这个联合索引去匹配。
- 但是如果遇到范围查询(>、<、between、like),就会停止,但是其左侧的字段依然可以走索引
- 原理:
- 由于MySQL底层是一颗B+树,联合索引也是一颗B+树
-
只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。
- like aa%后模糊查询索引有效,like %aa模糊查询索引无效
-
-
**InnoDB会把主键字段放到索引定义字段后面, 当然同时也会去重。 所以,当主键是(a,b)的时候, 定义为c的索引,实际上是(c,a,b); 定义为(c,a)的索引,实际上是(c,a,b) 你看着加是相同的 ps 定义为(c,b)的索引,实际上是(c,b,a)。**这时候再根据具体情况来对索引进行优化。
唯一索引和普通索引的区别
从数据查询来看
首先,MySQL底层是B+实现,利用二分法来定位到数据位置。
- 如果是范围查找,普通索引并没有唯一索引的唯一性,这样的话,假如现在要查询 id = 3 的索引,由于普通索引不一定唯一,所以需要在查询到id = 3的索引后再往后查询一个,判断其是否不为3,再结束;而唯一索引不需要,找到就停。
很显然,普通索引比唯一索引多一次查询,这一次查询如果是内存中查询基本没差,如果是磁盘IO可能还有点区别,然而引擎的读写是按照页来的,一页都读进内存,再来操作。所以,大概率是多一次内存的查询,没啥差别。
结论:从查询来看,唯一索引和普通索引并没有啥区别
从数据插入来看
这路需要介绍一个change buffer的概念:这个change buffer也是普通索引比唯一索引更快的原因。
先说结论,普通索引更快,因为普通索引可以使用change buffer来提升磁盘IO读写的效率,而唯一索引不可以使用change buffer因为唯一索引需要保证唯一性,本身就需要把数据读到内存中来判断,而且别忘了,是一页一页地读,再搞个change buffer纯属脱裤子放屁。
change buffer
我们知道,引擎会先把数据页读到内存中,再对数据进行查询和修改。如果我们要修改更新数据,就需要先找到修改的位置,这基本上就是查询过程。
所以,为了提高效率,如果是修改的数据此刻不在内存中,就会先把修改操作保存在change buffer中,然后等到下一次查询操作的时候,如果查到了修改的位置,就先执行操作,毕竟没有查询的话,修改就没有显式的作用。(让人联想到了我家猪猪🐖的ddl精神,有报告不写,诶,就是玩!等到截止时间前一晚再做,提高效率!)
两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响。所以,我建议你尽量选择普通索引。如果所有的更新后面,都马上伴随着对这个记录的查询,那么你应该关闭 change buffer。而在其他情况下,change buffer 都能提升更新性能。
将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。
merge
change buffer的merge操作,先把change buffer的操作更新到内存的数据页中,此操作写到redo log中,mysql未宕机,redo log写满后需要移动check point点时,通过判断内存中数据和磁盘是否一致即是否是脏页来刷新到磁盘中,当mysql宕机后没有内存即没有脏页,通过redo log来恢复。
redo log
redo log是物理日志,记录的是数据页的修改,但是如果数据页不在内存中怎么办呢?都没有去修改数据页,redo log中记什么?所以这时候change buffer登场了,如果修改的不是唯一索引,而是普通索引,不用再去磁盘随机IO了,直接将这个修改记录在change buffer中。也可以说,数据页在内存,那就修改数据页,写redo log,如果数据页不在内存,修改的也不是唯一索引,而是普通索引,那就写change buffer。并把这个change buffer写入到redo log,防止更新丢失。