索引篇:普通索引和唯一索引的使用
真实场景
线上某个插入量特别大的表中,从前一天起突然库的内存命中率从99% -> 75%,原因是DBA同学将这个表中的一个普通索引修改成了唯一索引。
那么,唯一索引和普通索引除了索引唯一的这一特性,查找,更新插入方式有区别吗?
查找过程
select id from T where k = 500
- 对唯一索引来说,查找的时候通过k的索引找到id = 500的那个值之后,停止查找。
- 对普通索引来说,查找的时候通过k的索引找到id = 500的那个值之后,继续遍历这棵树,知道找到满足条件的那个节点。
从查找来讲,性能上的差异微乎其微。
因为InnoDb读写一个数据的时候是按照页作为单位的,一个页的大小为16k,InnoDb会将这个页整个读到内存中去,然后再进行查找和寻根操作,而基本上一次查找大概率都会在一个页中,处于多个页中的情况比较少见,可以忽略不计。
更新过程
-
changeBuffer简介
当需要更新一个数据页时,需要先判断这个数据页是不是在内存中,如果不在,就需要将更新的这部分数据先写入到changeBuffer中,这样更新的时候就不用去频繁读取数据页了。下次如果读取从磁盘中读取数据,就会将changeBuffer的数据和数据页中的数据进行merge操作,保证读取数据的一致性。将changeBuffer数据应用到数据页,得到更新结果的操作叫做merge,除了访问数据会触发merge之外,还会有线程去定时进行merge操作,在数据库关闭的时候,也会触发merge操作。
changeBuffer在内存有拷贝,也会被写入到磁盘上,所以当机器断电,宕机的时候,changeBuffer也可以保证数据不会丢失。
-
changeBuffer使用场景
因为每次更新的时候会直接将数据写入到changeBuffer,减少读磁盘的开销,所以changeBuffer的适用场景也必须要有不读磁盘判断的前提条件。
如果这个表是写多读多,那么每次读取的时候都会触发一次changeBuffer的merge操作,这反而提升了随机IO,和changeBuffer的维护成本。
所以得到结论:changeBuffer只可以适用于普通索引,而不可适用于唯一索引,并且这个表是写多读少的场景。当前SQL操作语句:insert into T (id, name) VALUES (3, "jasper"),索引为id这个字段。
- 唯一索引:
- 如果id = 3数据在内存中,就直接判断3在表中是否存在,不存在就插入,存在就返回。
- 如果id = 3数据不在内存中,需要将数据页读到内存中,然后判断,执行插入或者返回。
- 普通索引
- 如果id = 3插入的位置在内存中,直接更新到内存中。
- 如果id = 3插入的位置不在内存中, 直接更新到changeBuffer中。
- 唯一索引:
-
changeBuffer和redoLog的区别
redoLog主要是解决随机写磁盘IO的问题,改成顺序写。
changeBuffer主要是解决随机读磁盘的IO问题。