InnoDB的关键特性-插入缓存,两次写,自适应hash索引详解

 更新时间:2017年4月3日 09:01  点击:1517

InnoDB存储引擎的关键特性包括插入缓冲两次写(double write)、自适应哈希索引(adaptive hash index)。这些特性为InnoDB存储引擎带来了更好的性能和更高的可靠性。

插入缓冲

插入缓冲是InnoDB存储引擎关键特性中最令人激动的。不过,这个名字可能会让人认为插入缓冲是缓冲池中的一个部分。其实不然,InnoDB缓冲池中有Insert Buffer信息固然不错,但是Insert Buffer和数据页一样,也是物理页的一个组成部分。

主键是行唯一的标识符,在应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引一般是顺序的,不需要磁盘的随机读取。

比如说我们按下列SQL定义的表:create table t(id int auto_increment,name varchar(30),primary key(id));

id列是自增长的,这意味着当执行插入操作时,id列会自动增长,页中的行记录按id执行顺序存放。一般情况下,不需要随机读取另一页执行记录的存放。因此,在这样的情况下,插入操作一般很快就能完成。但是,不可能每张表上只有一个聚集索引,在更多的情况下,一张表上有多个非聚集的辅助索引(secondary index)。比如,我们还需要按照name这个字段进行查找,并且name这个字段不是唯一的。

表是按如下的SQL语句定义的:create table t (id int auto_increment,name varchar(30),primary key(id),key(name));

这样的情况下产生了一个非聚集的并且不是唯一的索引。在进行插入操作时,数据页的存放还是按主键id的执行顺序存放,但是对于非聚集索引,叶子节点的插入不再是顺序的了。这时就需要离散地访问非聚集索引页,插入性能在这里变低了。然而这并不是这个name字段上索引的错误,因为B+树的特性决定了非聚集索引插入的离散性。

InnoDB存储引擎开创性地设计了插入缓冲,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页中,而是先判断插入的非聚集索引页是否在缓冲池中。如果在,则直接插入;如果不在,则先放入一个插入缓冲区中,好似欺骗数据库这个非聚集的索引已经插到叶子节点了,然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对非聚集索引执行插入和修改操作的性能。

插入缓冲的使用需要满足以下两个条件:

1.索引是辅助索引。

2.索引不是唯一的。

当满足以上两个条件时,InnoDB存储引擎会使用插入缓冲,这样就能提高性能了。不过考虑一种情况,应用程序执行大量的插入和更新操作,这些操作都涉及了不唯一的非聚集索引,如果在这个过程中数据库发生了宕机,这时候会有大量的插入缓冲并没有合并到实际的非聚集索引中。如果是这样,恢复可能需要很长的时间,极端情况下甚至需要几个小时来执行合并恢复操作。

辅助索引不能是唯一的,因为在把它插入到插入缓冲时,我们并不去查找索引页的情况。如果去查找肯定又会出现离散读的情况,插入缓冲就失去了意义。

查看插入缓冲的信息:

show engine innodb status\G

seg size显示了当前插入缓冲的大小为2*16KB,free list len代表了空闲列表的长度,size代表了已经合并记录页的数量。

下面一行可能是我们真正关心的,因为它显示了提高性能了。inserts代表插入的记录数,merged recs代表合并的页的数量,merges代表合并的次数。

merged recs:merges大约为3:1,代表插入缓冲将对于非聚集索引页的IO请求大约降低了3倍。

问题:

目前插入缓冲存在一个问题是,在写密集的情况下,插入缓冲会占用过多的缓冲池内存,默认情况下最大可以占用1/2的缓冲池内存。Percona已发布一些patch来修正插入缓冲占用太多缓冲池内存的问题,具体的可以到http://www.percona.com/percona-lab.html查找。简单来说,修改IBUF_POOL_SIZE_PER_MAX_SIZE就可以对插入缓冲的大小进行控制,例如,将IBUF_POOL_SIZE_PER_MAX_SIZE改为3,则最大只能使用1/3的缓冲池内存。

两次写

如果说插入缓冲带给InnoDB存储引擎的是性能,那么两次写带给InnoDB存储引擎的是数据的可靠性。当数据库宕机时,可能发生数据库正在写一个页面,而这个页只写了一部分(比如16K的页,只写前4K的页)的情况,我们称之为部分写失效(partial page write)。在InnoDB存储引擎未使用double write技术前,曾出现过因为部分写失效而导致数据丢失的情况。

有人也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚的是,重做日志中记录的是对页的物理操作,如偏移量800,写'aaaa'记录。如果这个页本身已经损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志前,我们需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页再进行重做,这就是doublewrite。

InnoDB存储引擎doublewrite的体系架构如图2-4所示

doublewrite由两部分组成:一部分是内存中的doublewrite buffer,大小为2MB;另一部分是物理磁盘上共享表空间中连续的128个页,即两个区(extent),大小同样为2MB(页的副本)。当缓冲池的脏页刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次写入1MB到共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite buffer中的页写入各个表空间文件中,此时的写入则是离散的。

可以通过以下命令观察到doublewrite运行的情况: show global status like 'innodb_dblwr%'\G

doublewrite一共写了18 445个页,但实际的写入次数为434,(42:1)   基本上符合64:1。

如果发现你的系统在高峰时Innodb_dblwr_pages_written:Innodb_dblwr_writes远小于64:1,那么说明你的系统写入压力并不是很高。

如果操作系统在将页写入磁盘的过程中崩溃了,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到改页的一个副本,将其拷贝到表空间文件,再应用重做日志。下面显示了由doublewrite进行恢复的一种情况: 

090924 11:36:32 mysqld restarted
090924 11:36:33 InnoDB:Database was not shut down normally!
InnoDB:Starting crash recovery.
InnoDB:Reading tablespace information from the.ibd files……
InnoDB:Error:space id in fsp header 0,but in the page header 4294967295
InnoDB:Error:tablespace id 4294967295 in file./test/t.ibd is not sensible
InnoDB:Error:tablespace id 0 in file./test/t2.ibd is not sensible
090924 11:36:33 InnoDB:Operating system error number 40 in a file operation.
InnoDB:Error number 40 means'Too many levels of symbolic links'.
InnoDB:Some operating system error numbers are described at
InnoDB:http://dev.mysql.com/doc/refman/5.0/en/operating-system-error-codes.html
InnoDB:File name./now/member
InnoDB:File operation call:'stat'.
InnoDB:Error:os_file_readdir_next_file()returned-1 in
InnoDB:directory./now
InnoDB:Crash recovery may have failed for some.ibd files!
InnoDB:Restoring possible half-written data pages from the doublewrite
InnoDB:buffer……

参数skip_innodb_doublewrite可以禁止使用两次写功能,这时可能会发生前面提及的写失效问题。不过,如果你有多台从服务器(slave server),需要提供较快的性能(如slave上做的是RAID0),也许启用这个参数是一个办法。不过,在需要提供数据高可靠性的主服务器(master server)上,任何时候我们都应确保开启两次写功能。

注意:有些文件系统本身就提供了部分写失效的防范机制,如ZFS文件系统。在这种情况下,我们就不要启用doublewrite了。 

自适应哈希索引

哈希(hash)是一种非常快的查找方法,一般情况下查找的时间复杂度为O(1)。常用于连接(join)操作,如SQL Server和Oracle中的哈希连接(hash join)。但是SQL Server和Oracle等常见的数据库并不支持哈希索引(hash index)。MySQL的Heap存储引擎默认的索引类型为哈希,而InnoDB存储引擎提出了另一种实现方法,自适应哈希索引(adaptive hash index)。

InnoDB存储引擎会监控表上索引的查找,如果观察到建立哈希索引可以带来速度的提升,则建立哈希索引,所以称之为自适应(adaptive)的。自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。而且不需要将整个表都建哈希索引,InnoDB存储引擎会自动根据访问的频率模式来为某些页建立哈希索引。

根据InnoDB的官方文档显示,启用自适应哈希索引后,读取和写入速度可以提高2倍;对于辅助索引的连接操作,性能可以提高5倍。自适应哈希索引是非常好的优化模式,其设计思想是数据库自优化(self-tuning),即无需DBA对数据库进行调整。

查看当前自适应哈希索引的使用状况:show engine innodb status\G

现在可以看到自适应哈希索引的使用信息了,包括自适应哈希索引的大小、使用情况、每秒使用自适应哈希索引搜索的情况。值得注意的是,哈希索引只能用来搜索等值的查询,如select * from table where index_col='xxx',而对于其他查找类型,如范围查找,是不能使用的。因此,这里出现了non-hash searches/s的情况。用hash searches:non-hash searches命令可以大概了解使用哈希索引后的效率。

由于自适应哈希索引是由InnoDB存储引擎控制的,所以这里的信息只供我们参考。不过我们可以通过参数innodb_adaptive_hash_index来禁用或启动此特性,默认为开启。

以上这篇InnoDB的关键特性-插入缓存,两次写,自适应hash索引详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

[!--infotagslink--]

相关文章

  • MySQL的InnoDB引擎入门学习教程

    MySQL发展到今天,InnoDB引擎已经作为绝对的主力,除了像大数据量分析等比较特殊领域需求外,它适用于众多场景。然而,仍有不少开发者还在“执迷不悟”的使用MyISAM引擎,觉得对InnoDB无法把握好,还是MyISAM简单省事,还能支持快...2015-11-24
  • 简单了解mysql InnoDB MyISAM相关区别

    这篇文章主要介绍了简单了解mysql InnoDB MyISAM相关区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-05
  • MySQL禁用InnoDB引擎的方法

    一、确定版本查看MySQL版本复制代码 代码如下:mysql -V或者可以登录MySQL使用select version();或status;命令查看二、开始工作关闭MySQL复制代码 代码如下:service mysql stop如果上面的命令无法关闭MySQL,则使用kill...2014-05-31
  • Mysql判断表字段或索引是否存在

    这篇文章主要介绍了Mysql判断表字段或索引是否存在的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下...2016-06-12
  • MySQL数据库优化技术之索引使用技巧总结

    这篇文章主要介绍了MySQL数据库优化技术之索引使用方法,结合实例形式总结分析了MySQL表的优化、索引设置、SQL优化等相关技巧,非常具有实用价值,需要的朋友可以参考下...2016-07-29
  • MySQL索引用法实例分析

    这篇文章主要介绍了MySQL索引用法,结合实例形式较为详细的分析了mysql索引的功能、定义、使用方法与相关注意事项,需要的朋友可以参考下...2016-07-29
  • 浅谈mysql的索引设计原则以及常见索引的区别

    下面小编就为大家带来一篇浅谈mysql的索引设计原则以及常见索引的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2017-04-03
  • MySQL InnoDB ReplicaSet(副本集)简单介绍

    这篇文章主要介绍了MySQL InnoDB ReplicaSet(副本集)的相关资料,帮助大家更好的理解和学习使用MySQL,感兴趣的朋友可以了解下...2021-04-23
  • MySQL提示The InnoDB feature is disabled需要开启InnoDB的解决方法

    这篇文章主要介绍了MySQL提示The InnoDB feature is disabled需要开启InnoDB的解决方法,简单分析了MySQL数据库开启InnoDB引擎的实现技巧,需要的朋友可以参考下...2016-01-15
  • mysql innodb的监控(系统层,数据库层)

    这篇文章主要介绍了mysql innodb的监控(系统层,数据库层)的相关资料,需要的朋友可以参考下...2017-04-26
  • MySQL InnoDB表空间加密示例详解

    这篇文章主要给大家介绍了关于MySQL InnoDB表空间加密的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-08-17
  • MySQL存储引擎简介及MyISAM和InnoDB的区别

    MyISAM:默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。注意,通过更改 STORAGE_ENGINE 配置变量,能够方便地更改MySQL服务器的默认存储引擎。 InnoDB:用于事务处理应用程序,具有众...2014-05-31
  • 详解MySQL InnoDB存储引擎的内存管理

    这篇文章主要介绍了详解MySQL InnoDB存储引擎的内存管理,帮助大家更好的理解和学习使用MySQL数据库,感兴趣的朋友可以了解下...2021-04-08
  • MySQL数据库innodb启动失败无法重启的解决方法

    这篇文章给大家分享了MySQL数据库innodb启动失败无法重启的解决方法,通过总结自己遇到的问题分享给大家,让遇到同样问题的朋友们可以尽快解决,下面来一起看看吧。...2016-10-02
  • InnoDb 体系架构和特性详解 (Innodb存储引擎读书笔记总结)

    下面小编就为大家带来一篇InnoDb 体系架构和特性详解 (Innodb存储引擎读书笔记总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2017-04-03
  • mysql中索引与FROM_UNIXTIME的问题

    这篇文章主要介绍了mysql中索引与FROM_UNIXTIME的问题的相关资料,需要的朋友可以参考下...2017-05-25
  • MySQL事务数据库(InnoDB类型)的安装方法

    MySQL数据库分二种类型,一种是传统的数据表格式,一种是支持事务处理的数据表格式(InnoDB,BDB,其中以InnoDB为主),下面我介绍一下关于MySQL事务处理数据库的安装及使用方...2016-11-25
  • MySQL中对于索引的基本增删查改操作总结

    这篇文章主要介绍了MySQL中对于索引的基本增删查改操作总结,索引可以提高MySQL的检索速度,需要的朋友可以参考下...2016-01-21
  • Mysql使用索引实现查询优化

    索引的目的在于提高查询效率,本文给大家介绍Mysql使用索引实现查询优化技巧,涉及到索引的优点等方面的知识点,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧...2016-08-23
  • Mysql数据库之索引优化

    MySQL凭借着出色的性能、低廉的成本、丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库。本文给大家介绍mysql数据库之索引优化,感兴趣的朋友一起学习吧...2016-04-07