2.1 InnoDB存储引擎概述

InnoDB 存储引擎最早由 Innobase Oy 公司开发,被包括在 MySQL 数据库所有的二进制发行版本中,从 MySQL 5.5 版本开始是默认的表存储引擎(之前的版本 InnoDB存储引擎仅在 Windows 下为默认的存储引擎)。该存储引擎是第一个完整支持 ACID 事务的 MySQL 存储引擎(BDB 是第一个支持事务的 MySQL 存储引擎,现在已经停止开发),其特点是行锁设计、支持 MVCC、支持外键、提供一致性非锁定读,同时被设计用来最有效地利用以及使用内存和 CPU。
Heikki Tuuri(1964 年,芬兰赫尔辛基)是InnoDB 存储引整的创始人,和著名的Linux 创始人 Linus 是芬兰赫尔辛基大学校友。在 1990 年获得赫尔辛基大学的数学逻辑博士学位后,他于1995 年成立 Innobase Oy 公司并担任 CEO。同时,在 InnoDB存储引擎的开发团队中,有来自中国科技大学的 Calvin Sun。而最近又有一个中国人 Jimmy Yang 也加入了InnoDB 存储引擎的核心开发团队,负责全文索引的开发,其之前任职于 Sybase 数据库公司,负责数据库的相关开发工作。
InnoDB存储引擎已经被许多大型网站使用,如用户熟知的 Google、Yahoo!、 Facebook、YouTube、Flickr,在网络游戏领域有《魔兽世界》、《Second Life》、《神兵玄奇》等。我不是 MySQL 数据库的布道者,也不是 InnoDB 的鼓吹者,但是我认为当前实施一个新的 OLTP 项目不使用 MySQL InnoDB 存储引擎将是多么的愚蠢。
从 MySQL 数据库的官方手册可得知,著名的 Internet 新闻站点 Slashdot.org运行在 InnoDB 上。Mytrix、Inc.在 InnoDB上存储超过1TB 的数据,还有一些其他站点在 InnoDB上处理插入/更新操作的速度平均为 800 次/秒。这些都证明了InnoDB 是一个高性能、高可用、高可扩展的存储引擎。
InnoDB存储引擎同 MySQL 数据库一样,在 GNU GPL 2下发行。更多有关 MySQL证书的信息,可参考http://www.mysql.com/about/legal/,这里不再详细介绍。

2.2 InnoDB 存储引擎的版本

  • 从 MySQL 5.1 版本时,MySQL 数据库允许存储引擎开发商以动态方式加载引擎,这样存储引擎的更新可以不受 MySQL 数据库版本的限制。
  • 所以在 MySQL 5.1中,可以支持两个版本的 InnoDB,一个是静态编译的 InnoDB 版本,可将其视为老版本的 InnoDB;另一个是动态加载的 InnoDB 版本,官方称为 InnoDB Plugin,可将其视为 InnoDB 1.0.x版本。MySQL5.5版本中又将 InnoDB 的版本升级到了
    1.1.x。
    而在最近的 MySQL 5.6 版本中InnoDB的版本也随着升级为1.2.x 版本。表2-1 显示了各个版本中 InnoDB存储引擎的功能。

2.3 InnoDB体系结构

InnoDB 存储引擎有多个内存块,可以认为这些内存块组成了—个大的内存池,负责如下工作∶

  • 维护所有进程 / 线程需要访问的多个内部数据结构。
  • 缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存。
  • 重做日志(redo log)缓冲。

    后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下 InnoDB 能恢复到正常运行状态。

2.3.1 后台线程

InnoDB 存储引擎是多线程的模型,因此其后台有多个不同的后台线程,负责处理不同的任务。

  1. Master Thread
    Master Thread 是一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(INSERT BUFFER)、 UNDO 页的回收等。

  2. IO Thread
    在 InnoDB存储引擎中大量使用了 AIO(Async IO)来处理写 IO 请求,这样可以极大提高数据库的性能。而 IO Thread 的工作主要是负责这些 IO 请求的回调(call back)处理。InnoDB 1.0 版本之前共有 4个 IO Thread,分别是 write、read、insert buffer 和 log IO thread。在 Linux 平台下,IO Thread的数量不能进行调整,但是在 Windows 平台下可以通过参数 innodb_file_io_threads 来增大 IO Thread。从 InnoDB 1.0.x 版本开始,read thread和 write thread分别增大到了4个,并且不再使用 innodb_file_io_threads 参数,而是分别使用 innodb_read_io_threadsinnodb_write_io_threads 参数进行设置。

    使用show engine innodb status; 查看
    可以看到IO Thread 0为 insert buffer thread。IO Thread 1为 log thread。之后就是根据参数 innodb_read_io_threads 及 innodb_write_io_threads来设置的读写线程,并且读线程的ID总是小于写线程。

  3. Purge Thread事务被提交后,其所使用的 undolog 可能不再需要,因此需要 PurgeThread来回收已经使用并分配的 undo 页。在 InnoDB 1.1版本之前,purge 操作仅在 InnoDB存储引擎的 Master Thread 中完成。而从 InnoDB 1.1 版本开始,purge操作可以独立到单独的线程中进行,以此来减轻 Master Thread 的工作,从而提高 CPU 的使用率以及提升存储引擎的性能。可以在配置文件中添加如下命令来启用独立的 Purge Thread:

[mysq1d]
innodb_purge_threads=1

在 InnoDB 1.1 版本中,即使将 innodb_purge_threads 设为大于1,InnoDB存储引擎启动时也会将其设为 1,并在错误文件中出现如下类似的提示∶

120529 22:54:16[Warning] option'innodb-purge-threads': unsigned value 4 adjusted to 1

从 InnoDB 1.2 版本开始,InnoDB支持多个 Purge Thread,这样做的目的是为了进一步加快 undo 页的回收。同时由于Purge Thread 需要离散地读取 undo 页,这样也能更进一步利用磁盘的随机读取性能。如用户可以设置 4个 Purge Thread∶

  1. Page Cleaner Thread
    Page Cleaner Thread 是在 InnoDB 1.2.x 版本中引入的。其作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。而其目的是为了减轻原 Master Thread 的工作及对于用户查询线程的阻塞,进一步提高 InnoDB存储引擎的性能。

2.3.2 内存

  1. 缓冲池
  • InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可将其视为基于磁盘的数据库系统(Disk-base Database)。在数据库系统中,由于 CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。
  • 缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页"FIX"在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
  • 对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 Checkpoint 的机制刷新回磁盘。同样,这也是为了提高数据库的整体性能。
  • 综上所述,缓冲池的大小直接影响着数据库的整体性能。由于 32 位操作系统的限制,在该系统下最多将该值设置为 3G。此外用户可以打开操作系统的 PAE选项来获得 32 位操作系统下最大 64GB 内存的支持。随着内存技术的不断成熟,其成本也在不断下降。因此为了让数据库使用更多的内存,强烈建议数据库服务器都采用 64 位的操作系统。
  • 对于 InnoDB 存储引擎而言,其缓冲池的配置通过参数 innodb_buffer_pool_size来设置。下面显示一台 MySQL 数据库服务器,其将 InnoDB存储引擎的缓冲池设置为 15GB。 单位为B。
  • 具体来看,缓冲池中缓存的数据页类型有∶索引页、数据页、undo 页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)、数据字典信息(data dictionary)等。不能简单地认为,缓冲池只是缓存索引页和数据页,它们只是占缓冲池很大的一部分而已。图 2-2 很好地显示了InnoDB 存储引擎中内存的结构情况。
  • 从 InnoDB 1.0.x 版本开始,允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。这样做的好处是减少数据库内部的资源竞争,增加数据库的并发处理能力。可以通过参数 innodb_buffer_pool_instances 来进行配置,该值默认为1。

  • 在配置文件中将 innodb_buffer_pool_instances 设置为大于1的值就可以得到多个缓冲池实例。再通过命令 SHOW ENGINE INNODB STATUS 可以观察到如下的内容
  • 这里将参数 innodb_buffer_pool instances设置为2,即数据库用户拥有两个缓冲池实例。通过命令 SHOW ENGINE INODB STATUS 可以观察到每个缓冲池实例对象运行的状态,并且通过类似—BUFFER POOL0的注释来表明是哪个缓冲池实例。
  • 从 MySQL5.6 版本开始,还可以通过information_schema架构下的表INNODB_BUFFER_POOL_STATS来观察缓冲的状态,如运行下列命令可以看到各个缓冲池的使用状态∶
  1. LRU List、Free List和 Flush List
  • 通常来说,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的。即最频繁使用的页在 LRU 列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放 LRU 列表中尾端的页。
  • 在 InnoDB 存储引擎中,缓冲池中页的大小默认为 16KB,同样使用LRU 算法对缓冲池进行管理。 InnoDB 存储引擎对传统的 LRU 算法做了一些优化。
  • 在InnoDB 的存储引擎中,LRU列表中还加入了midpoint 位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到LRU 列表的首部,而是放入到 LRU列表的 midpoint位置。这个算法在 InnoDB 存储引擎下称为 midpoint insertion strategy
  • 在默认配置下,该位置在 LRU 列表长度的 5/8 处。midpoint 位置可由参数innodb_old_blocks_pct 控制,如∶
  • 在 InnoDB 存储引擎中,把 midpoint 之后的列表称为 old 列表,之前的列表称为 new 列表。可以简单地理解为 new列表中的页都是最为活跃的热点数据。
  • 那为什么不采用朴素的 LRU 算法? 这是因为若直接将读取到的页放入到LRU 的首部,那么某些 SOL 操作可能会使缓冲池中的页被刷新出,从而影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的热点数据。如果页被放入 LRU 列表的首部,那么非常可能将所需要的热点数据页从 LRU列表中移除,而在下一次需要读取该页时,InnoDB 存储引擎需要再次访问磁盘。
  • 为了解决这个问题,InnoDB存储引擎引入了另一个参数来进一步管理 LRU 列表,这个参数是 innodb_old_blocks_time,用于表示页读取到 mid 位置后需要等待多久才会被加入到LRU 列表的热端。因此当需要执行上述所说的 SQL 操作时,可以通过下面的方法尽可能使LRU 列表中热点数据不被刷出。


如果用户预估自己活跃的热点数据不止 63%,那么在执行 SQL 语句前,还可以通过下面的语句来减少热点页可能被刷出的概率。

  • LRU 列表用来管理已经读取的页,但当数据库刚启动时,LRU 列表是空的,即没有任何的页。这时页都存放在 Free 列表中。当需要从缓冲池中分页时,首先从 Free 列表中查找是否有可用的空闲页,若有则将该页从 Free 列表中删除,放入到LRU列表中。否则,根据LRU 算法,淘汰 LRU 列表末尾的页,将该内存空间分配给新的页。当页从 LRU列表的 old 部分加入到 new 部分时,称此时发生的操作为 page made young,而因为innodb_old_blocks_time的设置而导致页没有从 old 部分移动到 new 部分的操作称为 page not made young。可以通过命令 SHOW ENGINE INNODB STATUS 来观察LRU 列表及 Free 列表的使用情况和运行状态。
  • 通过命令 SHOW ENGINE INNODB STATUS 可以看到∶当前 Buffer pool size共有 327 679个页,即327679*16K,总共 5GB的缓冲池。
  • Free buffers 表示当前 Free 列表中页的数量。
  • Database pages 表示LRU 列表中页的数量。可能的情况是 Free buffers 与 Database pages 的数量之和不等于 Buffer pool size。正如图 所示的那样,因为缓冲池中的页还可能会被分配给自适应哈希索引、Lock 信息、Insert Buffer 等页,而这部分页不需要 LRU 算法进行维护,因此不存在于LRU 列表中。
  • pages made young 显示了LRU 列表中页移动到前端的次数,因为该服务器在运行阶段没有改变 innodb_old_blocks_time 的值,因此 not young为 0。
  • youngs/s、non-youngs/s表示每秒这两类操作的次数。
  • 这里还有一个重要的观察变量——Buffer pool hit rate,表示缓冲池的命中率,这个例子中为 100%,说明缓冲池运行状态非常良好。通常该值不应该小于 95%。若发生 Buffer pool hit rate 的值小于 95% 这种情况,用户需要观察是否是由于全表扫描引起的 LRU 列表被污染的问题。

执行 SHOW ENGINE INNODB STATUS 显示的不是当前的状态,而是过去某个时间范围内 InnoDB 存储引擎的状态。从上面的例子可以发现,Per second averages calculated from the last 24 seconds 代表的信息为过去 24 秒内的数据库状态。

从 InnoDB 1.2 版本开始,还可以通过表INNODB_BUFFER_POOL_STATS 来观察缓冲池的运行状态,如∶

此外,还可以通过表INNODB_BUFFER_PAGE_LRU 来观察每个LRU 列表中每个页的具体信息,例如通过下面的语句可以看到缓冲池 LRU列表中 SPACE 为1 的表的页类型∶

  • InnoDB存储引擎从1.0.x 版本开始支持压缩页的功能,即将原本 16KB 的页压缩为 1KB、2KB、4KB和8KB。而由于页的大小发生了变化,LRU列表也有了些许的改变。对于非 16KB的页,是通过 unzip LRU列表进行管理的。通过命令 SHOW ENGINE INNODB STATUS 可以观察到如下内容∶
  • 可以看到LRU 列表中一共有1539 个页,而 unzip_LRU 列表中有 156 个页。这里需要注意的是,LRU中的页包含了 unzip LRU 列表中的页。
  • 对于压缩页的表,每个表的压缩比率可能各不相同。可能存在有的表页大小为 8KB,有的表页大小为 2KB 的情况。unzip_LRU 是怎样从缓冲池中分配内存的呢?
  • 首先,在 unzip LRU 列表中对不同压缩页大小的页进行分别管理。其次,通过伙伴算法进行内存的分配。例如对需要从缓冲池中申请页为 4KB 的大小,其过程如下∶
    1)检查 4KB 的 unzip LRU 列表,检查是否有可用的空闲页;
    2)若有,则直接使用;
    3)否则,检查 8KB的 unzip LRU 列表;
    4)若能够得到空闲页,将页分成2 个 4KB 页,存放到 4KB 的 unzip_LRU列表;
    5)若不能得到空闲页,从 LRU列表中申请一个16KB 的页,将页分为1个 8KB的页、2个 4KB的页,分别存放到对应的 unzip LRU 列表中。
    同样可以通过 information_schema 架构下的表 INNODB_BUFFER_PAGE_LRU 来观察 unzip_LRU 列表中的页,如∶
  • 在LRU 列表中的页被修改后,称该页为脏页(dirty page)即缓冲池中的页和磁盘上的页的数据产生了不一致这时数据库会通过 CHECKPOINT 机制将脏页刷新回磁盘,而 Flush 列表中的页即为脏页列表。需要注意的是,脏页既存在于LRU列表中,也存在于 Flush 列表中。LRU 列表用来管理缓冲池中页的可用性,Flush 列表用来管理将页刷新回磁盘,二者互不影响。
  • 同 LRU列表一样,Flush列表也可以通过命令 SHOW ENGINE INNODB STATUS来查看,前面例子中 Modified db pages 24673 就显示了脏页的数量。information_ schema架构下并没有类似INNODB_BUFFER_PAGE_LRU 的表来显示脏页的数量及脏页的类型,但正如前面所述的那样,脏页同样存在于LRU列表中,故用户可以通过元数据表 INNODB_BUFFER_PAGE LRU 来查看,唯一不同的是需要加入 OLDEST MODIFICATION 大于0的 SQL 查询条件,如∶

    可以看到当前共有4 个脏页及它们对应的表和页的类型。TABLE NAME 为 NULL表示该页属于系统表空间。
  1. 重做日志缓冲
  • InnoDB 存储引擎的内存区域除了有缓冲池外,还有重做日志缓冲(redo log buffer)。InnoDB存储引擎首先将重做日志信息先放入到这个缓冲区,然后按一定频率将其刷新到重做日志文件。重做日志缓冲一般不需要设置得很大,因为一般情况下每一秒钟会将重做日志缓冲刷新到日志文件,因此用户只需要保证每秒产生的事务量在这个缓冲大小之内即可。该值可由配置参数innodb_log_buffer_size 控制,默认为 8MB。
  • 在通常情况下,8MB 的重做日志缓冲池足以满足绝大部分的应用,因为重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中。
  1. Master Thread 每一秒将重做日志缓冲刷新到重做日志文件;
  2. 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
  3. 当重做日志缓冲池剩余空间小于 1/2 时,重做日志缓冲刷新到重做日志文件。

4.额外的内存池
额外的内存池通常被 DBA忽略,他们认为该值并不十分重要,事实恰恰相反,该值同样十分重要。在 InnoDB 存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池中进行申请。例如,分配了缓冲池(innodb_buffer_pool),但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffer control block),这些对象记录了一些诸如 LRU、锁、等待等信息,而这个对象的内存需要从额外内存池中申请。因此,在申请了很大的 InnoDB 缓冲池时,也应考虑相应地增加这个值。

2.1 InnoDB存储引擎(概述、版本、体系结构)相关推荐

  1. 不同存储结构的文件磁盘io操作次数_MySQL InnoDB存储引擎

    第1章 MySQL体系结构和存储引擎 1.1数据库和实例 数据库:物理操作系统文件或其他形式文件类型的集合.实例:MySQL数据库由后台线程以及一个共享内存区组成.共享内存可以被运行 的后台线程所共享 ...

  2. MySql技术内 幕:InnoDB存储引擎 读书笔记

    书名 <MySql技术内幕:InnoDB存储引擎> 作者 姜承尧 书摘 第一章:MySQL体系结构和存储引擎 定义数据库和实例: 定义数据库和实例 数据库:文件的集合,frm.MYD.MY ...

  3. 《MySQL技术内幕:InnoDB存储引擎》第2版笔记

    第1章 MySQL体系结构和存储引擎 1.1 定义数据库和实例 在MySQL数据库中,数据库文件可以是fm.MYD.MYI.ibd结尾的文件. MySQL数据库由后台线程以及一个共享内存区组成. My ...

  4. MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01

    MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01 1. MySQL体系结构和存储引擎 1.1 定义数据库和实例 数据库database: 物理操作系统文件或其他形式文件类型的集合. 当使 ...

  5. 《MySQL技术内 幕 InnoDB存储引擎》读书笔记

    MySQL技术内幕 LnnoDB存储引擎 读书笔记 1 MySQL 体系结构和存储引擎 1.1 数据库和数据库实例 数据库:物理操作系统文件活其他形式文件类型的集合 ​ 实例:MySQL数据库是由后台 ...

  6. MySQL技术内幕 InnoDB存储引擎——第2章 InnoDB存储引擎(未完待续)

    第2章 InnoDB存储引擎 2.1 InnoDB存储引擎概述 InnoDB存储引擎是第一个完整支持ACID事务的MySQL存储引擎(BDB是第一个支持事务的MySQL存储引擎,现在已经停止开发). ...

  7. mysql idataparameter_MySQL技术内幕——InnoDB存储引擎笔记

    第一章 MySQL体系结构和存储引擎 1.1 定义数据库和实例 数据库 :物理操作系统文件或其他形式类型文件的集合 实例 : MySQL数据库由后台线程以及一个共享内存区组成. Mysql数据库实例在 ...

  8. mysql技术内幕innodb存储引擎——表索引算法和锁_(转)Mysql技术内幕InnoDB存储引擎-表索引算法和锁...

    表 原文:http://yingminxing.com/mysql%E6%8A%80%E6%9C%AF%E5%86%85%E5%B9%95innodb%E5%AD%98%E5%82%A8%E5%BC% ...

  9. InnoDB 存储引擎详细解析

    InnoDB存储引擎详细解析 仅作为笔记 文章目录 InnoDB存储引擎详细解析 前言 一.InnoDB 存储引擎概述 二.InnoDB 存储引擎的版本 三.InnoDB 体系架构 3.1 后台线程 ...

  10. InnoDB存储引擎--InnoDB存储引擎

    文章目录 1. InnoDB存储引擎概述 2. InnoDB存储引擎的版本 3. InnoDB体系架构 (1). 后台线程 1). Master Thread 2). IO Thread 3). Pu ...

最新文章

  1. js的Prototype属性 解释及常用方法
  2. 从零开始学习docker(十四)Docker Compose--部署SpringCloud
  3. SWT外观:自定义FlatScrollBar颜色等
  4. 李学勤:功利化是现在教育的最大问题
  5. 如何修复:There is no command installed for 7-zip archive files
  6. 【数学工具?拉普拉斯机制?随机响应?】差分隐私系统学习记录(二)
  7. Cordova安装与配置过程中出现的问题及解决办法
  8. 数据--第50课 - 基础查找课后练习
  9. 阅读《经济学人》,学会这样查词典,从此英语学习不求人
  10. chrome 常用快捷键(可以摆脱鼠标哦)(转载)
  11. 朴素贝叶斯分类器常用的三种条件概率模型:伯努利、多项式、高斯模型
  12. YOLOv5目标检测算法——通俗易懂的解析
  13. CCPP Blog 目录
  14. 人生性格、爱情与酒场哲学
  15. 保利威视后台编辑FLASH播放器
  16. mysql dump 1449_Mysqldump 1449 错误解决 mysqldump: Got error: 1449
  17. 傻瓜攻略(十六)——MATLAB实现txt文件复杂内容的读取
  18. “大神”===“一万个小时的敲代码时间,100多万行的代码”
  19. 车联网目前在我国主要的应用市场
  20. java后台查询手机号码归属地

热门文章

  1. Linux驱动基础知识(一)
  2. vb利用计算机 鸡兔同笼,VB程序题:利用计算机解决古代数学瓿“鸡兔同笼问题”。即已知在同一笼子里有总数为m只鸡和兔,鸡和兔的总脚数为n只,求鸡和兔各有多少只? VB源码 龚沛曾...
  3. 局域网arp攻击_图解ARP协议(二)ARP攻击原理与实践
  4. 破解密码很难?利用Python自动编写暴力破解字典,黑客必学技能!
  5. 基于JAVA_JSP电子书下载系统
  6. 科大讯飞语音接口调用实现语音识别
  7. UNIX系统V(System V)
  8. fir 低通 matlab,用MATLAB设计FIR滤波器
  9. SQL入门教程(一):基础知识
  10. Java项目——个人博客系统