在MySQL索引你真的会用吗?这篇文章中我们已经讲解过MySQL中有哪些索引,并且讲解了该怎么去创建索引,今天我们就来讲一讲MySQL中普通索引和唯一索引的区别,相信小伙伴们在工作中都使用过这两种索引类型,那这两种索引到底有什么不一样呢?我们从CRUD这几个方面来逐一讲解,有问题欢迎大家讨论指正!
这两种查询方式的性能差距微乎其微,原因是InnoDB底层是以页才存储数据,每一页都是16KB,在读取数据的时候不是只是将符合条件的记录读取出来,而是将记录所在的整页数据都读取出来放到内存中,这个内存就是buffer pool, 这样当读取到满足条件的记录后,就不需要再去读磁盘了,只需要有一次内存指针寻址和计算,但是当读取到的第一条记录正好是这页数据的最后一条,当取下一条数据的时候就需要去磁盘中读一次,相对来说麻烦一些,但是这种情况出现的概率极低,可以忽略不计。
唯一索引:
判断当前更新是否违反唯一性约束,也就是判断更新的值是否已经存在了,那就要把数据从磁盘读到内存中进行比较;
普通索引:
判断当前记录是否存在于buffer pool中,
如果在buffer pool中就直接更新内存数据,后台定时将更新同步到磁盘中;
如果不在buffer pool中就需要将数据从磁盘中读取出来放到内存中,更新内存,后台定时将更新同步到磁盘中;
唯一索引:
与更新类似,也需要将数据从磁盘读取到内存中,判断新插入的值是否已经存在了,如果不存在就插入值(随机写磁盘),语句执行结束
普通索引:
找到位置直接插入值(随机写),语句执行结束
唯一索引和普通索引一样,都需要找到对应的磁盘位置,然后删除(随机读、随机写)
可以看到在“更新”和“插入”逻辑中,唯一索引为了保证唯一性都不可避免的需要将数据从磁盘中读到内存中进行判断,而普通索引则不需要进行唯一性判断,但是也需要将数据读取到内存中,都涉及了“随机读”;
插入操作都涉及了写磁盘操作;“删除”操作涉及了“随机读”和“随机写”。
众所周知“随机读”和“随机写”对性能的影响是很大的,因此InnoDB设计了ChangeBuffer,用来避免在执行SQL时的“随机读”和“随机写”。
只对普通索引有效,因为唯一索引都需要将数据读取到内存中进行唯一性判断(除了删除操作),Change buffer属于buffer pool。
上边讲到了ChangeBuffer的“被动”merge时机,当ChangeBuffer中的数据所在页涉及到查询时,就会被merge,假如说我们的业务是**“写多读少”**,那非常适合适用ChangeBuffer;如果我们的业务是写完立刻读的场景多,那ChangeBuffer就没有什么意义了,随机读写的次数不会减少,还增加了维护Change buffer的代价。
ChangeBuffer的持久化是通过Redo log来实现的,下边会进行讲解
先来看执行插入的完整流程:
redo日志有分几十种类型的。
redo做的事情,简单讲就是记录页的变化(WAL将页变化的乱序写转换成了顺序写)。页是分多种的,比如 B+树索引页(主键 / 二级索引)、undo页(数据的多版本MVCC)、以及现在的change buffer页等等,这些页被redo记录后,就可以不着急刷盘了。change buffer记录索引页的变化;但是change buffer本身也是要持久化的,而它持久化的工作和其他页一样,交给了redo日志来帮忙完成;redo日志记录的是change buffer页的变化。
change buffer持久化文件是 ibdata1,索引页持久化文件是 t.ibd,所以Redo log也可以用来恢复change buffer。
这样changebuffer与redo log的区别就显而易见了: