缓冲池是主内存中的一个区域,在InnoDB访问表和索引数据时会在其中进行 缓存。缓冲池允许直接从内存中直接处理经常使用的数据,从而加快了处理速度。在专用服务器上,通常将多达80%的物理内存分配给缓冲池。
为了提高大容量读取操作的效率,缓冲池被分为多个页面,这些页面可能包含多个行。为了提高缓存管理的效率,缓冲池被实现为page的链接列表。使用LRU算法的变体将很少使用的数据从缓存中老化掉 。
知道如何利用缓冲池将经常访问的数据保留在内存中是MySQL优化的重要方面。
使用最近最少使用(LRU)算法的变体,将缓冲池作为列表进行管理。当需要空间以将新页面添加到缓冲池时,将驱逐最近使用最少的页面,并将新页面添加到列表的中间。此中点插入策略将列表视为两个子列表:
最前面是最近访问过的新页面(“ 年轻 ”) 的子列表
该算法将大量页面保留在新的子列表中。旧的子列表包含较少使用的页面。这些页面是驱逐的候选对象 。
默认情况下,该算法的运行方式如下:
3/8的缓冲池专用于旧的子列表。
列表的中点是新子列表的尾部与旧子列表的头相交的边界。
当InnoDB将页面读入缓冲池时,它首先将其插入中点(旧子列表的头部)。可以读取页面,因为它是用户启动的操作(例如SQL查询)所必需的,或作为的自动执行的预读操作的一部分 InnoDB。
访问旧子列表中的页面 使其变为“ 年轻 ”,将其移至新子列表的头部。如果由于用户启动的操作而需要读取页面,则将立即进行首次访问,并使页面年轻。如果由于预读操作而读取了该页面,则第一次访问不会立即发生,并且在退出该页面之前可能根本不会发生。
随着数据库的运行,通过移至列表的尾部,缓冲池中未被访问的页面将“ 老化 ”。新的和旧的子列表中的页面都会随着其他页面的更新而老化。随着将页面插入中点,旧子列表中的页面也会老化。最终,未使用的页面到达旧子列表的尾部并被逐出。
默认情况下,查询读取的页面会立即移入新的子列表,这意味着它们在缓冲池中的停留时间更长。例如,针对mysqldump操作或SELECT不带WHERE子句的 语句 执行的表扫描可以将大量数据带入缓冲池,并驱逐同等数量的旧数据,即使不再使用新数据也是如此。同样,由预读后台线程加载且仅访问一次的页面将移到新列表的开头。这些情况可能会将常用页面推送到旧的子列表,在此它们会被逐出。有关优化此行为的信息,请参见 第14.8.3.3节“使缓冲池扫描具有抵抗力”和 第14.8.3.4节“配置InnoDB缓冲池预取(预读)”。
InnoDB标准监视器输出在BUFFER POOL AND MEMORY有关缓冲池LRU算法操作的部分中包含几个字段。有关详细信息,请参阅使用InnoDB Standard Monitor监视缓冲池。
理想情况下,您可以将缓冲池的大小设置为与实际一样大的值,从而为服务器上的其他进程留出足够的内存以运行而不会进行过多的分页。缓冲池越大,就越InnoDB像内存数据库一样,从磁盘读取一次数据,然后在后续读取期间从内存访问数据。请参见 第14.8.3.1节“配置InnoDB缓冲池大小”。
在具有足够内存的64位系统上,可以将缓冲池分成多个部分,以最大程度地减少并发操作之间的内存结构争用。有关详细信息,请参见第14.8.3.2节“配置多个缓冲池实例”。
您可以将频繁访问的数据保留在内存中,而不必考虑操作突然导致的活动高峰,这些操作会将大量不经常访问的数据带入缓冲池。有关详细信息,请参见 第14.8.3.3节“使缓冲池扫描具有抵抗力”。
您可以控制何时以及如何执行预读请求,以异步方式将页面预取到缓冲池中,从而预期很快将需要这些页面。有关详细信息,请参见第14.8.3.4节“配置InnoDB缓冲池预取(预读)”。
您可以控制何时进行后台冲洗,以及是否根据工作负荷动态调整冲洗速率。有关详细信息,请参见 第14.8.3.5节“配置缓冲池刷新”。
您可以配置如何InnoDB保留当前缓冲池状态,以免在服务器重新启动后进行冗长的预热。有关详细信息,请参见 第14.8.3.6节“保存和恢复缓冲池状态”。
您可以InnoDB在服务器运行时脱机(启动时)或联机配置缓冲池大小。本节中描述的行为适用于两种方法。有关在线配置缓冲池大小的更多信息,
当增加或减
少时 innodb_buffer_pool_size,将按块执行操作。块大小由innodb_buffer_pool_chunk_size 配置选项定义 ,其默认值为 128M。有关更多信息,请参见 配置InnoDB缓冲池块大小。
缓冲池大小必须始终等于innodb_buffer_pool_chunk_size* 或* 的倍数 innodb_buffer_pool_instances。如果配置 innodb_buffer_pool_size为不等于innodb_buffer_pool_chunk_size* 或 * innodb_buffer_pool_instances的值,则缓冲池大小将自动调整为等于innodb_buffer_pool_chunk_size* 或 *的值 innodb_buffer_pool_instances。
在以下示例中, innodb_buffer_pool_size设置为8G,并且 innodb_buffer_pool_instances设置为16。 innodb_buffer_pool_chunk_size 是128M,这是默认值。
8G是有效值, innodb_buffer_pool_size因为它是 * 8G的倍数 ,即。 innodb_buffer_pool_instances=16innodb_buffer_pool_chunk_size=128M2G
该innodb_buffer_pool_size 配置选项可以动态使用设置 SET声明,让您调整缓冲池无需重新启动服务器。例如:
mysql> SET GLOBAL innodb_buffer_pool_size=402653184;
活动交易和通过执行的操作 InnoDB在调整缓冲池大小之前,应先完成API。启动调整大小操作时,该操作直到所有活动事务完成后才开始。调整大小操作正在进行后,需要访问缓冲池的新事务和操作必须等待直到调整大小操作完成。该规则的例外是,在对缓冲池进行碎片整理时,允许并发访问缓冲池;在减小缓冲池大小时,将撤回页面。允许并发访问的缺点是,在撤回页面时,这可能会导致可用页面的暂时短缺。
注意
如果在缓冲池调整大小操作开始后启动嵌套事务,则事务可能失败。
更改缓冲区是一种特殊的数据结构,当二级索引页不在缓冲池中时,它们 会缓存这些更改 。当页面通过其他读取操作加载到缓冲池中时,可能由INSERT, UPDATE或 DELETE操作(DML)导致的缓冲更改 将在以后合并。
与聚簇索引不同,二级索引通常是非唯一的,并且二级索引中的插入以相对随机的顺序发生。同样,删除和更新可能会影响索引树中不相邻的二级索引页。当稍后通过其他操作将受影响的页读入缓冲池时,合并缓存的更改将避免从磁盘将辅助索引页读入缓冲池所需的大量随机访问I / O。
在系统大部分处于空闲状态或缓慢关闭期间运行的清除操作会定期将更新的索引页写入磁盘。与将每个值立即写入磁盘相比,清除操作可以更有效地为一系列索引值写入磁盘块。
当有许多受影响的行和许多辅助索引要更新时,更改缓冲区合并可能需要几个小时。在此期间,磁盘I / O会增加,这可能会导致磁盘绑定查询的速度大大降低。提交事务之后,甚至在服务器关闭并重新启动之后,更改缓冲区合并也可能继续发生( 有关更多信息,请参见第14.22.2节“强制InnoDB恢复”)。
在内存中,更改缓冲区占用了缓冲池的一部分。在磁盘上,更改缓冲区是系统表空间的一部分,当数据库服务器关闭时,索引更改将存储在其中。
更改缓冲区中缓存的数据类型由 innodb_change_buffering变量控制。有关更多信息,请参见 配置变更缓冲。您还可以配置最大更改缓冲区大小。有关更多信息,请参见 配置更改缓冲区最大大小。
如果索引包含降序索引列或主键包含降序索引列,则辅助索引不支持更改缓冲。
有关更改缓冲区的常见问题的答案,请参见第A.16节“ MySQL 5.7 FAQ:InnoDB更改缓冲区”。
哪些类型的操作会修改二级索引并导致更改缓冲?
INSERT,,UPDATE和 DELETE操作可以修改二级索引。如果受影响的索引页不在缓冲池中,则可以将更改缓冲在更改缓冲区中。
当二级索引页不在缓冲池中时,对二级索引更改进行缓冲可以避免昂贵的随机访问I / O操作,该操作可能需要立即从磁盘中读取受影响的索引页。当页面被其他读取操作读取到缓冲池中时,缓冲的更改可以稍后批量应用。
-更改缓冲区是否支持其他类型的索引?
否。更改缓冲区仅支持二级索引。不支持聚簇索引,全文索引和空间索引。全文索引具有自己的缓存机制。
innodb_change_buffer_max_size 在MySQL 5.6中 引入配置选项之前, 系统表空间中磁盘更改缓冲区的最大大小为InnoDB缓冲池大小的1/3 。
在MySQL 5.6和更高版本中, innodb_change_buffer_max_size 配置选项将更改缓冲区的最大大小定义为总缓冲池大小的百分比。默认情况下, innodb_change_buffer_max_size 设置为25。最大设置为50。
InnoDB 如果会导致磁盘上的更改缓冲区超过定义的限制,则不会缓冲操作。
更改缓冲区页不需要保留在缓冲池中,并且可以由LRU操作逐出。
标题SHOW ENGINE INNODB STATUS \G下的 会报告更改缓冲区的当前大小 INSERT BUFFER AND ADAPTIVE HASH INDEX。例如:
Ibuf:大小1,空闲列表len 0,seg大小2,0合并
相关数据点包括:
size:更改缓冲区内使用的页数。更改缓冲区的大小等于seg size - (1 + free list len)。该1 +值表示更改缓冲区标题页。
seg size:更改缓冲区的大小(以页为单位)。
有关监视更改缓冲区状态的信息,请参见 第14.5.2节“更改缓冲区”。
将页面读入缓冲池时,在页面可用之前,缓冲的更改会在读取完成后合并。
更改缓冲区合并作为后台任务执行。该 innodb_io_capacity 参数设置由InnoDB后台任务执行的I / O活动的上限,例如合并来自更改缓冲区的数据。
在崩溃恢复期间执行更改缓冲区合并。当将索引页读入缓冲池时,更改将从更改缓冲区(在系统表空间中)应用于辅助索引的叶页。
更改缓冲区是完全耐用的,并且可以在系统崩溃后幸免。重新启动后,更改缓冲区合并操作将恢复为正常操作的一部分。
可以使用强制将更改缓冲区完全合并为缓慢的服务器关闭的一部分 --innodb-fast-shutdown=0。
更新的页面将通过与刷新占用缓冲池的其他页面相同的刷新机制进行刷新。
更改缓冲区是一项旨在减少随索引变大而不再适合InnoDB缓冲池的二级索引的随机I / O的功能。通常,当整个数据集不能容纳到缓冲池中时,当大量的DML活动会修改二级索引页面时,或者当许多二级索引因DML活动而定期更改时,都应使用更改缓冲区。
如果整个数据集都适合InnoDB缓冲池,或者二级索引相对较少,或者您使用的是固态存储(其中随机读取的速度与顺序读取的速度差不多),则可以考虑禁用更改缓冲区。在进行配置更改之前,建议您使用具有代表性的工作负载运行测试,以确定禁用更改缓冲区是否可以带来任何好处。
配置变更缓冲
在表上执行,和 操作时INSERT, 索引列的值(尤其是辅助键的值)通常处于未排序的顺序,需要大量的I / O才能使辅助索引保持最新状态。当相关页面不在 缓冲池中时,更改缓冲区将 更改缓存到辅助索引条目 ,从而避免了不立即从磁盘读取页面而避免了昂贵的I / O操作。当页面加载到缓冲池中时,缓冲的更改将合并,更新的页面随后将刷新到磁盘。的UPDATEDELETEInnoDB当服务器接近空闲时以及在缓慢关闭期间,主线程会合并缓冲的更改 。
由于更改缓冲区功能可以减少磁盘读写操作,因此它对于受I / O约束的工作负载(例如,具有大量DML操作的应用程序,例如批量插入)最有价值。
但是,更改缓冲区占用了缓冲池的一部分,从而减少了可用于缓存数据页的内存。如果工作集几乎适合缓冲池,或者您的表具有相对较少的二级索引,则禁用更改缓冲可能很有用。如果工作数据集完全适合缓冲池,则更改缓冲不会带来额外的开销,因为它仅适用于不在缓冲池中的页面。
您可以InnoDB 使用innodb_change_buffering 配置参数来控制执行更改缓冲 的程度。您可以为插入,删除操作(最初将索引记录标记为删除)和清除操作(物理删除索引记录)启用或禁用缓冲。更新操作是插入和删除的组合。默认 innodb_change_buffering值为 all。
允许的innodb_change_buffering 值包括:
all
默认值:缓冲区插入,删除标记操作和清除。
none
不要缓冲任何操作。
inserts
缓冲区插入操作。
deletes
缓冲区删除标记操作。
changes
缓冲插入和删除标记操作。
purges
缓冲在后台发生的物理删除操作。
您可以innodb_change_buffering在MySQL选项文件(my.cnf或 my.ini)中设置 参数,或使用SET GLOBAL 语句动态更改参数,该 语句需要足够的权限来设置全局系统变量。请参见 第5.1.8.1节“系统变量特权”。更改设置会影响新操作的缓冲。现有缓冲条目的合并不受影响。
配置更改缓冲区最大大小
该innodb_change_buffer_max_size 变量允许将更改缓冲区的最大大小配置为缓冲池总大小的百分比。默认情况下, innodb_change_buffer_max_size设置为25。最大设置为50。
考虑innodb_change_buffer_max_size在具有大量插入,更新和删除活动的MySQL服务器上进行增加 ,其中更改缓冲区合并不能跟上新的更改缓冲区条目,从而导致更改缓冲区达到其最大大小限制。
考虑innodb_change_buffer_max_size在使用静态数据进行报告的MySQL服务器上减少 ,或者如果更改缓冲区消耗了与缓冲池共享的太多内存空间,从而导致页面比期望的更快地从缓冲池中老化。
使用代表性的工作负载测试不同的设置,以确定最佳配置。该 innodb_change_buffer_max_size 设置是动态的,允许在不重新启动服务器的情况下修改设置。
自适应哈希索引功能可以InnoDB 在不牺牲事务功能或可靠性的情况下,在工作负载和缓冲池有足够内存的适当组合的系统上,更像是内存数据库。自适应哈希索引功能由innodb_adaptive_hash_index 变量启用 ,或在服务器启动时由禁用 --skip-innodb-adaptive-hash-index。
根据观察到的搜索模式,使用索引关键字的前缀构建哈希索引。该前缀可以是任何长度,并且可能是哈希树索引中仅B树中的某些值出现。哈希索引是根据对经常访问的索引页面的需求而建立的。
如果表几乎完全适合主内存,则散列索引可以通过启用直接查找任何元素的方式来加速查询,从而将索引值转换为某种指针。InnoDB 具有监视索引搜索的机制。如果 InnoDB发现查询可以从构建哈希索引中受益,它会自动这样做。
在某些工作负载下,哈希索引查找的速度大大超过了监视索引查找和维护哈希索引结构的额外工作。在繁重的工作负载(例如多个并发连接)下,访问自适应哈希索引有时可能会成为争用的源。与 LIKE运算符和% 通配符也往往不会受益。对于无法从自适应哈希索引功能中受益的工作负载,将其关闭可减少不必要的性能开销。由于很难预先预测自适应哈希索引功能是否适合特定的系统和工作负载,因此请考虑启用和禁用该功能的基准测试。与早期版本相比,MySQL 5.6中的体系结构更改使其更适合禁用自适应哈希索引功能。
在MySQL 5.7中,自适应哈希索引功能已分区。每个索引都绑定到一个特定的分区,并且每个分区都受到单独的锁存器的保护。分区由innodb_adaptive_hash_index_parts 变量控制 。在较早的版本中,自适应哈希索引功能受单个闩锁的保护,在繁重的工作负载下,它可能成为争用点。该 innodb_adaptive_hash_index_parts 变量默认设置为8。最大设置为512。
您可以在输出SEMAPHORES部分中 监视自适应哈希索引的使用和争用 SHOW ENGINE INNODB STATUS。如果在中创建的RW锁上有许多线程在等待btr0sea.c,请考虑增加自适应哈希索引分区的数量或禁用自适应哈希索引功能。
有关哈希索引的性能特征的信息,请参见第8.3.8节“ B树和哈希索引的比较”。
日志缓冲区是存储区域,用于保存要写入磁盘上的日志文件的数据。日志缓冲区大小由innodb_log_buffer_size变量定义 。默认大小为16MB。日志缓冲区的内容会定期刷新到磁盘。较大的日志缓冲区使大型事务可以运行,而无需在事务提交之前将重做日志数据写入磁盘。因此,如果您有更新,插入或删除许多行的事务,则增加日志缓冲区的大小可以节省磁盘I / O。
该 innodb_flush_log_at_trx_commit 变量控制如何将日志缓冲区的内容写入并刷新到磁盘。该 innodb_flush_log_at_timeout 变量控制日志刷新频率。
有关相关信息,请参见“ 内存配置 ”和 第8.5.4节“优化InnoDB重做日志”。