-
一般情况下,主键是行唯一的标识符。通常应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引一般是顺序的,不需要磁盘的随机读取。因为,对于此类情况下的插入,速度还是非常快的。
-
如果索引是非聚集的且不唯一。在进行插入操作时,数据的存放对于非聚集索引叶子节点的插入不是顺序的,这时需要离散地访问非聚集索引页,由于随机读取的存在而导致了插入操作性能下降。这是因为B+树的特性决定了非聚集索引插入的离散性。
聚集索引与非聚集索引的最大区别:
聚集索引叶子节点保存的是主键索引和行完整数据, 非聚集索引叶子节点存放的是辅助索引和指向聚集索引中数据的指针
-
所以插入缓冲为解决非聚集索引的写性能问题(插入或更新)而设计
-
对非聚集索引的插入或更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在则直接插入;不在则先放入到一个Insert Buffer对象中,此时起到了欺骗的效果,看似数据库这个非聚集索引已经插入到了叶子节点,然而并非如此,只是存放在另一个位置。然后再以一定的频率以及情况进行Insert Buffer同辅助索引页子节点的merge操作,此时通常能将多个插入合并到一个操作中,这就大大提高了非聚集索引插入的性能。
-
Insert Buffer的数据结构是一棵B+树,现在的MySQL版本中,全局只有一棵Insert Buffer B+树,负责对所有的表的辅助索引进行Insert Buffer,而这棵B+树存放在共享表空间中,即ibdata1中。Master Thread线程中每秒或每10秒会进行一次Merge Insert Buffer的操作
-
Insert Buffer的使用要满足以下两个条件:
索引是辅助索引
索引不是唯一的
-
innodb的数据页一般大小是16KB,MySQL存取数据的最小单位也是页,而操作系统并不能保障一个数据页的原子性,也就是说当写入数据时,有可能在一个页中写入一半时(比如8K)数据库宕机,这种情况称为部分写失效(partial page write),从而导致数据丢失。
-
大家也许会问,难道我不可以根据redo / undo log进行数据恢复吗?答案是肯定的也是否定的,要分为两种情况:1、数据库宕机,物理文件完好无损,是可以通过redo log进行崩溃恢复。2、数据库宕机,正在刷新到磁盘的页发生partial page write,而正好在磁盘上的这个物理文件由于宕机发生损坏,这时就无法通过redo log进行数据恢复了, 于是在这种特殊情况下,doublewrite就派上用场啦!
-
doublewrite分为两部分,一部分是内存中的doublewrite buffer,大小2M,另一部分是磁盘上共享表空间的连续128个页,大小也是2M。对缓冲池脏页进行刷新时,先用memcpy函数将脏页复制到内存的doublewrite buffer,然后由doublewrite buffer再分为两次,每次1MB顺序写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。 doublewrite页(共享表空间的页)是连续的,所以这是一个顺序的过程,并没有很大的开销。若操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite页中找到该页的一个副本,复制到表空间文件再应用重做日志。完成共享表空间相关的写入后,再将doublewrite buffer中的页写入各个表空间文件中,而此时的写入则是离散的,因为各个表空间可能在磁盘的不同位置。
-
如果操作系统在将页写入磁盘的过程中发生了崩溃,恢复过程中,InnoDB可以从共享表空间中的doublewrite中找到该页的一个副本,将其复制到表空间文件,再应用重做日志。
-
简述步骤就是:
-
将脏页辅助到doublewrite buffer
-
将doublewrite buffer分批次写入到共享表空间中, 因为共享表空间是连续存储所以很快
-
然后再将doublewrite buffer中数据写入到各个表空间文件中, 而此时的写入则是离散的,因为各个表空间可能在磁盘的不同位置.
- 参数skip_innodb_doublewrite可以禁用doublewrite功能,可能导致前面提及的写失效问题,对于需要提供数据高可靠性的主服务器(master server),任何时候都应该确保开启doublewrite功能。
-
哈希是一种非常快的查找方法,在一般情况时间复杂度为O(1)。而B+树的查找次数,取决于B+树的高度,在生成环境中,B+树的高度一般为3-4层,不需要查询3-4次。
-
InnoDB存储引擎会监控对表上各索引页的查询。如果观察到简历哈希索引可以提升速度,这简历哈希索引,称之为自适应哈希索引(Adaptive Hash Index, AHI)。AHI是通过缓冲池的B+树页构造而来的。因此建立的速度非常快,且不要对整张表构建哈希索引。InnoDB存储哟inquiry会自动根据房屋的频率和陌生来自动的为某些热点页建立哈希索引。
-
AHI有一个要求,对这个页的连续访问模式(查询条件)必须一样的。例如联合索引(a,b)其访问模式可以有以下情况:
WHERE a=XXX;
2.WHERE a=xxx AND b=xxx。
- 若交替进行上述两张查询,InnoDB存储引擎不会对该页构造AHI。此外AHI还有如下要求:
a.以该模式访问了100次;
b.页通过该模式访问了N次,其中N=页中记录/16。
- 根据官方文档显示,启用AHI后,读取和写入的速度可以提高2倍,负责索引的链接操作性能可以提高5倍。其设计思想是数据库自由化的,无需DBA对数据库进行人为调整。
-
为了提高磁盘操作性能,当前的数据库系统都采用异步IO的方式来处理磁盘操作。InnoDB也是如此。
-
与AIO对应的是Sync IO,即每进行一次IO操作,需要等待此次操作结束才能继续接下来的操作, 也就是同步阻塞式的。但是如果用户发出的是一条索引扫描的查询,那么这条SQL语句可能需要扫描多个索引页,也就是需要进行多次IO操作(扫描一个页就是一次io请求)。在每扫描一个页并等待其完成再进行下一次扫描,这是没有必要的。用户可以在发出一个IO请求后立即再发出另外一个IO请求,当全部IO请求发送完毕后,等待所有IO操作完成,这就是AIO的异步非阻塞。
-
AIO的另外一个优势是进行IO Merge操作,也就是将多个IO合并为一个IO操作,这样可以提高IOPS的性能。
-
在InnoDB 1.1.x之前,AIO的实现是通过InnoDB存储引擎中的代码来模拟的。但是从这之后,提供了内核级别的AIO的支持,称为Native AIO。Native AIO需要操作系统提供支持。Windows和Linux都支持,而Mac则未提供。在选择MySQL数据库服务器的操作系统时,需要考虑这方面的因素。
-
MySQL可以通过参数innodb_use_native_aio来决定是否启用Native AIO。在InnoDB存储引擎中,read ahead方式的读取都是通过AIO完成,脏页的刷新,也是通过AIO完成。
引擎中,read ahead方式的读取都是通过AIO完成,脏页的刷新,也是通过AIO完成。