更新的流程

当需要更新一条记录的时候,如果数据页在内存中就直接更新,而如果这个数据页不在内存中的话,在不影响数据一致性的前提下,InnoDB会先把这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。
在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行changebuffer中与这个数据页相关的操作。通过这种方式就能保证这个数据逻辑的正确性。
将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge。除了访问这个数据页会触发merge外,系统有后台线程会定期执行merge。在数据库正常关闭的过程中也会执行merge。
如果能够将更新操作先放在change buffer中,减少读磁盘,语句的执行速度会得到明显的提升。同时,数据读入内存是会占用buffer pool的,这种方式还能够避免占用内存,提高内存利用率,change buffer是占用buffer pool里的内存,因此不能无限增大。可以通过innodb_change_buffer_max_size来动态设置。这个参数设置为50的时候,表示change buffer的大小最多只能占用buffer pool的50%

针对查询过程

  1. 在索引树上的查询流程是,先通过B+树从树根开始,按层搜索到叶子节点
  • 对于普通索引来说,查找到满足条件的第一条记录之后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录
  • 对于唯一索引来说,查找到满足条件的第一条记录之后,就会停止检索。

      那这个不同带来的性能查询会有多少呢?答案是微乎其微<br />            InnoDB的数据是按页来读的。当需要读一条记录的时候,并不是将这个记录从磁盘读取出来,而是以页为单位,将其整体读入内存。在InnoDB中,每个数据也页的大小为16kb<br />            对于普通索引来说,只是在内存中查找并判断下一条记录是否符合条件,只是需要一次指针寻找和一次计算。如果这个记录正好是这个数据页的最后一条,那就要再读出下一页,这个操作会稍微复杂一些(需要注意的是,整型字段,一个数据页可以存放近千个key,因此出现这种情况的概率很低,所以计算性能差异时,可以认为这个操作成本对于现在的CPU来说可以忽略不计)
    

    针对更新过程

  • 对于唯一索引来说,每次更新都要判断是否违反唯一约束 ,比如要插入一条记录,就要先判断这条记录在表中是否已经存在了,而这个判断是必须要将数据读入内存才可以的。但是都已经读入内存了就不用change buffer了,直接更新内存会更快。因此唯一索引的更新是不能使用change buffer的,也只有有普通索引才可以使用。

    将数据从磁盘读入内存设计随机IO的访问,是数据库里面成本最高的操作之一。

  • 对于普通索引来说,直接将更新操作记录在change buffer中,语句就执行结束了。

    如果是唯一索引,还需要将数据页从磁盘中读取到内存中判断是否违反了唯一约束,所以不用使用change buffer ,涉及磁盘的随机读,性能消耗较大。
    因此change buffer对于普通索引来说,对性能的提升是很明显的。

    change buffer的使用场景

    前提:因为merge的时候才是真正机进行数据更新的时刻,而change buffer的主要目的就是将记录的变更动作缓存下来,所以在一个数据页做merge之前,changebuffer记录的变更越多,那么收益就越大。
    merge是在数据页被读到的时候才会merge,因此对于写多读少的业务来来说,数据页被写完之后马上被访问到的概率比较小,此时change buffer的使用效果最好,反过来,假设一个业务的更新模式是写完之后马上就查询,那么即使满足了条件,将更新先记录在change buffer中,但之后又立刻访问这个数据页,会立即触发merge过程。这样随机访问IO的次数不会减少, 反而增加了维护change buffer的代价。因此针对读多的业务来说,change buffer会起到反作用。

    merge的执行流程

  1. 从磁盘读入数据页到内存中(老版本数据页)
  2. 从change buffer中找出这个数据页的change buffer,依次应用,得到新版本的数据页
  3. 记入redo log。这个redo log包括了数据页的变更和change buffer的变更

数据页和内存中的change buffer对应的磁盘位置的数据都 还没有修改,对应的数据页属于脏页,刷脏就又是另一个流程了。

更新语句的流程

1、如果要更新的数据页在内存中,那么就直接更新内存<br />    2、如果要更新的数据页不内存中,那么就把这次更新操作记录在change buffer中(唯一索引不会,唯一索引会把数据页读入内存进行判断是否违反了唯一性约束)<br />    3、将上述两个动作记入redo log中