InnoDB存储引擎

来源:互联网 发布:专业校色软件 编辑:程序博客网 时间:2024/06/15 00:33

 InnoDB存储引擎在设计之初,参考了Jim Gray和Andreas Reuter在1993年编写的《Transaction Processing Concepts and Techniques》,Gary在书中完整地解释了事务型存储引擎的回滚、前滚和死锁等概念以及简单实现,
另外InnoDB的设计也参照了当时非常流行的Oracle架构和功能。除此之外,InnoDB还具备独有的特性:
    双写入:这一技术指的是当InnoDB在进行表空间数据写操作时会将数据写两次(写日志时只写一次)。
插入缓冲:插入缓存的存在减少了数据库在对非主索引插入数据时,造成的磁盘随机读写情况。
适应式哈希索引:如果一个表能完全可以载入到主内存,在其上执行查询最快的方式就是使用哈希索引,
InnoDB 是一个自动机制,它监视对为一个 表定义的索引的索引搜索,如果InnoDB注意到查询会尽力
一个哈希索引中获益,它会自动的这样做。

InnoDB是为处理超大型数据量时获得最大性能而设计的,它的CPU效率可能是任何

其他基于磁盘的关系型数据库引擎所不能匹敌的。


    InnoDB存储引擎早期随着MySQL数据库的更新而更新,从MySQL5.1版本时,MySQL数据库允许存储引擎开发商以动态方式加载引擎,这样的存储引擎在更新可以不受MySQL数据库版本的限制,所以在MySQL5.1版本中,可以支持两个版本的InnoDB,一个是静态编译的InnoDB版本,可将其视为老版本的InnoDB;另一个动态加载的InnoDB版本官方称为InnoDB Plugin,可将其视为InnoDB1.0.X版本,MySQL5.5版本有奖InnoDB的版本升级到1.1.X,而在MySQL5.6版本中将InnoDB版本升级至1.2.X版本,如下图所示:


InnoDB Plugin不支持Linux Native AIO功能的;不支持多回滚段,所以支持最大并发事务数被限制在1023个。

InnoDB存储引擎架构:


  上图为InnoDB存储引擎的体系架构图,InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池

innodb存储引擎内存由以下三个部分组成:缓冲池(buffer pool)、重做日志缓存(redo log buffer)、额外的内存池(additional memory pool)。可以使用 show engine innodb status来查看innodb_buffer_pool的使用情况。

InnoDB存储引擎是多线程的模型,innodb存储引擎后台有7个线程,分别是1个master thread、4个IO线程(insert buffer thread、log thread、read thread、write thread)、1个lock监控线程、1个错误监控线程组成。后台线程的主要作用是负责刷新内存池的数据,保证缓冲池中的内存缓存的是最近的数据,此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下innoDB能恢复到正常状态,因此其后台有对个不同的后台线程,负责处理不同的任务:

一、后台线程

1、Master Thread:

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

2、IO Thread:

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


可以通过 show engine innodb status来观察InnoDB中的IO Thread:


可以看到IO Thread 0为insert buffer thread,IO Thread 1为log thread。之后就是根据参数innodb_read_io_threads和innodb_write_io_threads来设置的读写线程,并且读线程的ID总是小于写线程。

3、Purge Thread

   事务提交后,其所使用的undolog可能不在需要,因此需要Purge Thread来回收已经使用分配的undo页,在InnoDB1.1版本(MySQL5.5版本)之前,purge操作仅在InnoDB存储引擎的Master Thread中完成,而从InnoDB1.1版本开始,purge操作可以独立到单独的线程中进行,以此来减轻Master Thread的工作,从而提供CPU的使用率以及提升存储引擎的性能,在InnoDB1.1版本中即使将innodb_purge_threads设为大于1,InnoDB存储引擎启动时也会将其设为1,并在错误文件中出现如下类似的提示:

[Warning] option 'innodb_purge_threads':unsigned value 4 adjusted to 1……

从InnoDB1.2版本(MySQL5.6)开始,InnoDb支持多个Purge Thread 这样做的目的是为了进一步加快undo页的回收,同时由于Purge Thread需要离散地读取undo页,这样也能更进一步利用磁盘的随机性能。innodb_purge_threads参数的默认值为4


4、Page Cleaner Thread

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


二、内存

1、缓冲池

   InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。在数据库系统中,由于CPU速度与磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。缓冲池是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘读到的页内存放在(FIX)缓冲池中,下一次再读取相同的页时,首先判断该页是否在缓冲池中。若在,则直接读取该页,否则读取磁盘上的页。

    对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,为了提高数据库的整体性能,页从缓冲池刷新回磁盘并不是每次页发生更新时触发,而是通过checkpoint的机制刷新回磁盘。

    对于InnoDB存储引擎而言,其缓冲池配置可以通过innodb_buffer_pool_size来设置缓冲池的大小(默认128M)


    具体来看,缓冲池中缓冲的数据页类型有:索引页、数据页、undo页、插入缓冲(insertbuffer)、自适应哈希索引(adaptive hash index),InnoDB存储的锁信息(lock info)、数据字典信息(data dictionary)等。1.0.x版本开始,允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。好处是减少数据库内部的资源竞争,增加数据库的并发处理能力。可以通过innodb_buffer_pool_instances来进行配置,默认值为1,若大于1,则表示有多个缓冲池实例。



2、LRU List、Free List和Flush List

   通常数据库中的缓冲池是通过LRU(Lastest Recent Used,最近最少使用)算法来进行管理的。即最频繁使用的页放在LRU列表的前端,而最少使用的页放在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。
   在InnoDB中,缓冲池中页的大小默认为16KB。InnoDB对传统LRU算法进行了优化,在LRU列表中还加入了midpoint位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到LRU首部,而是放入到LRU列表的midpoint位置。这种算法在InnoDB存储引擎称为 midpoint insertion strategy,在默认配置下,该位置在LRU列表长度的5/8处,midpoint参数innodb_old_blocks_pct控制。


    innodb_old_blocks_pct参数的默认值为37,表示新读取到的页插入到LRU列表尾端的37%的位置(差不多3/8位置)。在InnoDB中把midpoint之后的列表称为old列表,之前的列表为new列表(最活跃的热点数据)。
    LRU朴素算法是直接将读取的页放入到LRU列表首部,若将读取到的页放入到LRU首部,那么某些SQL操作可能会使用缓冲池中的页被刷新出,从而影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页仅在这次查询中需要,并不是热点数据。如果这些页被放入首部,则热点数据会被从列表中移除,下次读取页时,InnoDB存储引擎需要从磁盘再次读取。
   为了解决这一问题,InnoDB存储引擎引入了另一个参数来进一步管理LRU列表,这个参数是innodb_old_blocks_time,用于表示页读取到mid位置后需要等待多久会加入到LRU列表的热端,默认1000ms(毫)




命令:SET GLOBAL innodb_old_blocks_time = 1000;





http://blog.csdn.net/taozhi20084525/article/details/17751819

内容学习来自《MySQL技术内幕-InnoDB存储引擎》--姜承尧 著

原创粉丝点击