一、InnoDB 索引
索引是数据库应用中非常重要的组成部分,可以提升数据检索效率,减轻服务引擎的压力。InnoDB 服务引擎,支持哈希索引和B+Tree索引。其中,B+Tree 是默认选择,也是最常用的索引结构。普通索引和唯一索引是最常用的两种索引类型,本文详细介绍一下两者的区别。
二、普通索引与唯一索引的作用
普通索引,规律分布在叶子节点上,唯一的目的就是方便随机查找和范围查找,提升检索效率。
唯一索引,不仅要实现普通索引的功能,还要保证值的唯一性。
三、普通索引与唯一索引的区别
change buffer
探讨两者的区别,需要从它们的作用机制入手。对于普通索引,change buffer 的作用至关重要,这也是其与唯一索引区别最大的地方。至于 change buffer 是什么,要从 MySQL 的数据管理机制说起。
为了减少 IO 读的次数,MySQL 将数据分别存在磁盘和内存中,磁盘中是原始数据,内存(buffer pool)中是缓存的数据页和索引页。可以说,buffer pool 是缓解磁盘读的一种手段。当然,MySQL 不会单单研究出来一个缓解磁盘读的机制,毕竟磁盘读和写都是十分消耗的操作,而 change buffer 就是缓解磁盘写的一种手段。
当需要更新一个数据页时,如果数据页在 buffer pool 中,则直接更新;如果不在缓存中,InnoDB 就会把更新操作缓存在 change buffer 中,而不会从磁盘中读取数据页到 buffer pool。在合适的时机,如再次访问这个数据页时,InnoDB 便会将数据页读入内存,然后执行 change buffer 中的相关操作。总之,在不影响数据逻辑正确性的前提下,减少了磁盘写的次数。
对于 InnoDB 数据引擎,将 change buffer 的操作应用到数据页的过程,叫 merge。以下场景会触发 merge 操作:
- 访问这个数据页;
- 系统后台线程定期 merge;
- change buffer 容量不够用时;
- 数据库正常关闭时;
- redo log 写满时(固定大小,循环写);
此外,虽然 change buffer 看起来像是一个临时缓存,但它却是可持久化的数据,不仅存于内存,也被写到磁盘上。这样的设计才是合理的,当出现突发状况时,可以通过磁盘上的 change buffer 恢复逻辑操作,保证数据的正确性和系统的容灾能力。
3.1 在查询方面的差异
id 是聚簇索引,k 是二级索引。可以看出,这是一个典型的索引覆盖场景。
1 | select id from T where k = 10; |
如果给 k 加上普通索引,那么随机查询将根据二分法找到第一个目标数据,然后再沿着叶子节点查找下一个数据,判断是否为 10,如果不是,则返回查询结果。
如果给 k 加上唯一索引,那么随机查询将根据二分法找到第一个目标数据,然后返回查询结果,因为这个目标数据一定是唯一的。
所以,在查询数据方面,普通索引比唯一索引多一个向下一个节点查找的步骤。如果下一个节点在同一个数据页,通过指针直接就可以拿到;如果下一个节点不在当前数据页,那么将会发生一次 IO 读。就是说,普通索引的查询性能弱于唯一索引。
3.2 在更新方面的差异
从 change buffer 的介绍可知,当数据页不在内存中,使用普通索引会将更新操作缓存在 change buffer 中,然后在适当的时机 merge 到原数据页中,从而减少 IO 次数;而使用唯一索引,为了保证数据的唯一性,需要将数据页读到内存中来,进行更新操作,再写回磁盘。就是说,普通索引的更新性能强于唯一索引。