一、唯一索引和普通索引的选择(Mysql实战45讲笔记-实践)
1.唯一索引和普通索引
1. 1 查询过程中的不同
在索引树查询的过程,通过B+树从树根开始,按层搜索到叶子节点。
比如select id from T where k=5
,搜索到的就是下图中右下角的数据页,然后可以认为数据页内部通过二分法来定位记录。
- 普通索引:查找到满足条件的第一条记录后,接着搜索下一个记录,知道第一个不满足k=5条件的记录。
- 唯一索引:查找到第一条满足条件的记录后,就会停止检索
两者的性能差距不大,因为InnoDb的数据是按照数据页
为单位来读写的,一个数据页的大小默认是16k,数据页是整体读到内存的,所以对于两种索引的搜索性能差别不大。
极特殊情况下,满足条件的记录是数据页最后一条记录,那普通索引在搜索下一个记录的时候,会读下个数据页的数据,这种情况下,普通索引的效率会高一些,不过对于整型字段,一个数据页可以放近千个key,所以满足条件的记录在数据页最后的概率比较低。
1.2 更新过程中的不同
1.2.1 change buffer 简介
唯一索引和普通索引在更新过程的差异,主要在于change buffer。首先解释一下什么是change buffer。
- 更新数据的步骤,两种情况:
- -> 数据所在的数据页在内存中 -> 直接更新内存
- -> 数据所在的数据页不在内存中 -> 将更新操作缓存在change buffer 中
- 查询上个步骤更新的数据 -> 将数据页读入内存 -> 根据change buffer中存储的操作,更新内存。
将change buffer中的操作应用到原数据页,得到最新的结果的过程称为merge
触发merge的三种情况:
- 通过访问这个数据页触发merge
- 系统后台线程也会定期meger
- 数据库正常关闭(shutdown)的时候也会merge
注意:
- change buffer 是可以持久的数据,它在内存中有拷贝,也会写在磁盘中
- change buffer 占用的是buffer pool的内存,通过设置
innoDB_change_buffer_max_size
参数,来设置占用buffer pool内存大小比例,如设置50,则占用50%- 通过将更新操作记录到change buffer,减少读磁盘,提高语句的执行效率,而且数据读入内存,也需要占用buffer pool ,这样也减少了内存占用
1.2.2 普通索引和唯一索引更新步骤
chang buffer 也不是适用所以场景,可以提高效率的。
例如唯一索引的更新操作,都会在更新操作前判断是否违反唯一性,所以先要进行读操作,这样更新数据的时候,就可以直接更新内存,就用不到change buffer了。
插入数据不同情况下,唯一索引和普通索引的插入步骤:
- 要更新的目录也在内存中:
- 唯一索引:找到位置后,判断没有冲突后插入,结束
- 普通索引:找到位置后,插入,结束
- 要更新的目录不在内存中:
- 唯一索引:将数据页加载到内存中,判断没有冲突后插入,结束
- 普通索引:将更新操作记录到change buffer,结束
将数据从磁盘读入内存涉及随机IO
的访问,是数据库中成本最高的操作。所以普通索引使用change buffer 减少了随机磁盘访问,对更新性能显著提高。
1.2.3 change buffer的使用场景
根据上一个小节,可以看到普通索引在更新的过程中使用change buffer,效率高于唯一索引的更新过程。但是普通索引也不是在所有情况下,通过使用change buffer可以提高性能的。
merge的时候,change buffer中存储的操作步骤越多,对于性能的提高越高
如果在进行更新操作后,马上又进行查询操作,就会马上触发merge,不但没有提高效率,还增加了维护change buffer的成本。
change buffer的适用场景:不会插入后马上去查询的场景,如日志类、账单类,
1.2.4 change buffer 和redo log
随后来补