一、几个名词
页
聚集索引&非聚集索引:
聚集索引是数据的实际存储顺序是按照索引的顺序存储的,非聚集索引是数据的物理存储顺序和索引顺序是无关的。innodb数据表本身就是一个索引表,表中的数据按照聚集索引顺序存储。
二、Innodb的五个关键特性
插入缓冲、两次写、自适应哈希索引、异步IO、刷新临近页
1.插入缓冲
插入缓冲是针对插入、更新、插入的数据存在非聚集索引时,为了提高插入、更新、插入非聚集索引的顺序而设计的。
由于innodb表数据是按照聚集索引顺序存储的,所以聚集索引的插入很快(物理上相邻),但是非聚集索引的插入或更新操作是随机插入,性能不高,即有了插入缓冲。
插入缓冲原理:对于非聚集索引的插入(包括更新、删除)操作,插入索引时,并不直接在索引页插入,而是判断要插入的非聚集索引是否在缓冲池中,如果在缓冲池中则进行插入操作,不在缓冲池中则先放在一个缓冲区中,并返回插入成功的结果,后台线程会以一定的频率进行插入缓冲和非聚集索引叶子结点的合并操作。这样能将多个插入操作合并到一个IO中。
举个例子
create table student (
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY(`id`), KEY(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入两条记录:
insert into student (name) values('Alice');
insert into student (name) values('Jack');
使用到插入缓冲的两个条件:
操作的索引为非聚集索引(聚集索引是连续的,速度快没必要使用插入缓冲)
索引不是唯一索引。数据插入时,不会根据非聚集索引来判断数据的唯一性,如果索引是唯一的就会查找索引页判断数据的唯一性,查找过程是随机的,这时插入缓冲就失去了意义
2.两次写
给InnoDB存储引擎带来的是数据页的可靠性。
当数据库发生宕机时,InnoDB存储引擎可能正在将某个脏页写到磁盘中,而这时这个页还没写完,就会出现丢数据的情况。redo log并不能解决这种情况,如果数据库宕机时磁盘的每个物理页完好无损,这时可以通过重做日志进行恢复,但是此刻正在由内存页写入的磁盘页,所以当前磁盘页是损坏的,比如,一个16k的磁盘页写了2k时断电了,此时当前磁盘页前2k数据是新的,后14k数据是旧的,这时在进行重做是没有意义的,这时候就用到了InnoDB的两次写来解决这个问题。

?xml version="1.0" encoding="UTF-8"?
doublewriter由两部分组成,一部分是内存中的doublewritebuffer,大小为2M,另一部分是磁盘中的共享表空间中连续的128个页,即2个区,大小也为2M。
两次写过程:
1)将缓冲池中脏页刷新到磁盘时,并不直接将脏页写入到磁盘的的数据文件中,而是首先拷贝至内存中的doublewriter buffer中.
2)接着两次写缓冲区分两次写入磁盘的共享表空间中,每次1M。(顺序存储顺序写,性能很高)
3)第二步完成后再将doublewriter buffer中数据写入实际的各个表空间文件。(完成后标记对应doublewriter数据可被覆盖)
3.自适应哈希索引AHI
innodb会监控表上各索引页的查询,如果监控到建立哈希索引会提高查询效率则会自动创建哈希索引。AHI是针对缓冲池中B+树页构造,并不是对整张表构造,索引速度很快。
自适应哈希索引的创建有个条件:连续多次查询某个页的查询条件必须是一样的。比如对(a,b)这样的索引页其查询条件可以是 where a=XX,或者where a=XX & b=XX,如果上边两种查询是交替进行的则innodb不会建立自适应哈希索引。
4.异步IO
先解释一下同步IO,同步IO即每进行一次IO操作必须等待操作结束才能进行下一次操作。比如用户发出了一条索引扫描的查询,那么这条sql可能扫描多个索引页,也就是需要进行多次IO操作,在每扫描一个页并等待其结束才能扫描下一个页,这是没有必要的,异步IO就是用户发出一个IO请求后可以立即发出下一个请求,所有请求发送完毕后等待所有IO操作的完成,这就是AIO。
5.刷新临近页
异步IO是innodb进行刷新脏页时,会检测该页所在的区内的所有页,如果存在脏页则会一块刷新,这样做的好处是可以将多次IO操作合并为一个IO。
网友评论