首页 > 数据库 > > 14.4 InnoDB 架构
参考官方文档:
https://dev.mysql.com/doc/refman/5.7/en/innodb-concepts.html
14.4.1 Buffer Pool
缓冲池是主内存中的区域,InnoDB在访问数据时缓存表和索引数据。 缓冲池允许经常使用的数据直接从内存中处理,从而加快处理速度。 在专用数据库服务器上,经常将高达80%的物理内存分配给InnoDB缓冲池。
为了提高高容量读取操作的效率,缓冲池分为可能包含多行的页面。 为了高速缓存管理的效率,缓冲池被实现做为页面的链接列表; 很少使用的数据使用LRU算法的变体超时缓存。
14.4.2 Change Buffer
更改缓冲区是一种特殊的数据结构,当受影响的页面不在缓冲池中时,缓存对二级索引页面的更改。 当页面通过其他读取操作加载到缓冲池中时,稍后可能会合并由INSERT,UPDATE或DELETE操作(DML)导致的缓冲更改。
与聚簇索引不同,二级索引经常是非唯一的,并以相对随机的顺序插入到二级索引中。同样,删除和更新可能会影响位于索引树中不相邻的二级索引页。 稍后合并缓存更改时,当受影响的页面通过其他操作读入缓冲池时,可避免从磁盘读入二级索引页面所需的大量随机访问I / O。
定期地,当系统大部分处于空闲状态或缓慢关闭期间时,运行清除操作会将更新后的索引页写入磁盘。 与每个值立即写入磁盘相比,清除操作可以更有效地为一系列索引值写入磁盘块。
当需要更新许多二级索引和许多受影响的行时,更改缓冲区合并可能需要几个小时。 在此期间,磁盘I / O会增加,这可能会导致磁盘绑定查询的显著减速。 事务提交后,更改缓冲区合并也可能继续发生。 事实上,在服务器关闭并重新启动后,更改缓冲区合并可能会继续发生(请参见第14.21.2节“强制InnoDB恢复”以获取更多信息)。
在内存中,更改缓冲区占据了InnoDB缓冲池的一部分。 在磁盘上,更改缓冲区是系统表空间的一部分,因此索引更改在数据库重新启动时保持缓冲。
缓存在更改缓冲区中的数据类型由innodb_change_buffering配置选项控制。 有关更多信息,请参见第14.6.5节“配置InnoDB更改缓冲”。 您还可以配置最大更改缓冲区大小。 有关更多信息,请参见第14.6.5.1节“配置更改缓冲区的最大大小”。
监控 change buffer
以下选项可用于更改缓冲区监视:
mysql> SHOW ENGINE INNODB STATUS\G
更改缓冲区状态信息位于INSERT BUFFER AND ADAPTIVE HASH INDEX标题下,并且类似于以下内容:
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX -------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 4425293,
used cells 32, node heap has 1 buffer(s)
13577.57 hash searches/s, 202.47 non-hash searches/s
mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME LIKE '%ibuf%'\G
警告:
查询INNODB_BUFFER_PAGE表可能会导致显着的性能开销。 为避免影响性能,请重新在测试实例上运行查询和调查问题。
例如,您可以查询INNODB_BUFFER_PAGE表以确定IBUF_INDEX和IBUF_BITMAP页面的大致数量,占总缓冲池页面的百分比。
mysql> SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages, (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages, (SELECT ((change_buffer_pages/total_pages)*100)) AS change_buffer_page_percentage;
+---------------------+-------------+-------------------------------+
| change_buffer_pages | total_pages | change_buffer_page_percentage |
+---------------------+-------------+-------------------------------+
| 25 | 8192 | 0.3052 |
+---------------------+-------------+-------------------------------+
mysql> SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE '%wait/synch/mutex/innodb/ibuf%';
+-------------------------------------------------------+---------+-------+
| NAME | ENABLED | TIMED |
+-------------------------------------------------------+---------+-------+
| wait/synch/mutex/innodb/ibuf_bitmap_mutex | YES | YES |
| wait/synch/mutex/innodb/ibuf_mutex | YES | YES |
| wait/synch/mutex/innodb/ibuf_pessimistic_insert_mutex | YES | YES |
+-------------------------------------------------------+---------+-------+
14.4.3 自适应哈希索引
自适应哈希索引(AHI)让InnoDB在系统上执行更像内存数据库,并为缓冲池提供适当的工作负载和充足内存组合,而不会牺牲任何事务功能或可靠性。 该功能由innodb_adaptive_hash_index选项启用,或者在服务器启动时通过--skip-innodb_adaptive_hash_index关闭。
根据观察到的搜索模式,MySQL使用索引键的前缀构建一个哈希索引。 key的前缀可以是任何长度,并且可能只有B树中的某些值出现在哈希索引中。 哈希索引是根据需要为经常访问的索引页面构建的。
如果一张表几乎完全在内存中,一个哈希索引可以通过直接查找任何元素来加快查询速度,将索引值转换为一种指针。 InnoDB有一个监控索引搜索的机制。 如果InnoDB注意到查询可以从构建散列索引中受益,它会自动完成
对于一些工作负载,哈希索引查找的加速大大超过了监视索引查找和维护哈希索引结构的额外工作。 有时候,保护访问自适应哈希索引的读/写锁可能成为工作负载繁重的争用源,如多个并发连接。 LIKE运算符和%通配符的查询也不会受益于AHI。 对于不需要自适应散列索引的工作负载,将其关闭可减少不必要的性能开销。 由于很难提前预测此功能是否适合特定系统,因此请考虑使用实际工作负载来启用和禁用启用和禁用基准。 MySQL 5.6和更高版本中的架构更改,比早期版本更适合禁用自适应哈希索引,但默认情况下它仍处于启用状态。
在MySQL 5.7中,自适应哈希索引搜索系统是分区的。 每个索引都绑定到一个特定的分区,每个分区受独立的latch保护。 分区由innodb_adaptive_hash_index_parts配置选项控制。 在早期版本中,自适应哈希索引搜索系统受单个锁存器的保护,该锁存器在繁重的工作负载下可能成为争用点。 innodb_adaptive_hash_index_parts选项默认设置为8。 最大设置是512。
哈希索引始终基于表上现有的B树索引构建。 InnoDB可以在为B树定义的任何密钥长度的前缀上构建一个哈希索引,具体取决于InnoDB观察到的B树索引的搜索模式。 哈希索引可以是部分的,仅覆盖索引经常访问的那些页面。
在SHOW ENGINE INNODB STATUS命令的输出的SEMAPHORES部分中的观察使用的争用情况。 如果在btr0sea.c中创建的RW-latch上看到许多线程在等待,那么禁用自适应散列索引可能会很有用。
14.4.4 redo log buffer
重做日志缓冲区是保存要写入重做日志的数据的内存区域。 重做日志缓冲区大小由innodb_log_buffer_size配置选项定义。 重做日志缓冲区会定期刷新到磁盘上的日志文件。 一个大的重做日志缓冲区允许大事务运行,而无需在事务提交之前将重做日志写入磁盘。 因此,如果您有更新,插入或删除多行的事务,则使日志缓冲区更大可节省磁盘I / O。
innodb_flush_log_at_trx_commit(默认是1,在提交就把log buffer的日志刷新到磁盘,一般设置为2,不立即flush到磁盘)选项控制如何将重做日志缓冲区的内容写入日志文件。 innodb_flush_log_at_timeout选项控制重做日志刷新频率(默认是1秒刷新一次)。
14.4.5 system 表空间
InnoDB系统表空间包含InnoDB数据字典(与InnoDB相关的对象的元数据),是双写缓冲区,更改缓冲区和撤消日志的存储区域。 系统表空间还包含在系统表空间中创建的任何用户创建表的表和索引数据。 系统表空间被视为共享表空间,因为它被多个表共享。
系统表空间由一个或多个数据文件表示。 默认情况下,在MySQL数据目录中创建一个名为ibdata1的系统数据文件。 系统数据文件的大小和数量由innodb_data_file_path启动选项控制。
例如:
innodb_data_home_dir = /data/mysql/mysql3306/data
innodb_data_file_path = ibdata1:1G:autoextend;ibdata2:12M:autoextend:max:500M
14.4.6 InnoDB 数据字典
InnoDB数据字典由内部系统表组成,这些系统表包含用于跟踪诸如表,索引和表格列等对象的元数据。 元数据物理位于InnoDB系统表空间中。 由于历史原因,数据字典元数据在一定程度上与存储在InnoDB表元数据文件(.frm文件)中的信息重叠。
14.4.7 双写buffer
双写缓冲区是位于系统表空间中的存储区域,InnoDB在页面写入数据文件中的正确位置之前写入从InnoDB缓冲池中刷新的页面。 只有在将页面刷新并写入双写缓冲区之后,InnoDB才会将页面写入其正确的位置。 如果操作系统,存储子系统或mysqld进程在页面写入过程中发生崩溃,InnoDB稍后可以在崩溃恢复期间从双写缓冲区中找到该页面的良好副本。
尽管数据总是写入两次,但双写缓冲区不需要两倍的I / O开销或两倍的I / O操作。 数据作为一个大的顺序块写入到双写缓冲区本身,并对操作系统进行一次fsync()调用。
在大多数情况下,默认情况下会启用doublewrite缓冲区。 要禁用双写缓冲区,请将innodb_doublewrite设置为0。
如果系统表空间文件(“ibdata文件”)位于支持原子写入的Fusion-io设备上,则会自动禁用双写缓冲,并将Fusion-io原子写入用于所有数据文件。 由于双写缓冲区设置是全局性的,所以对于驻留在非Fusion-io硬件上的数据文件,也会禁用双写缓冲。 此功能仅在Fusion-io硬件上受支持,并且仅适用于Linux上的Fusion-io NVMFS。 要充分利用此功能,建议使用innodb_flush_method设置O_DIRECT。
14.4.8 undo logs
撤消日志是与单个事务关联的撤消日志记录的集合。 撤销日志记录包含有关如何撤消事务对聚集索引记录的最新更改的信息。 如果另一个事务需要查看原始数据(作为一致读取操作的一部分),则从撤消日志记录中检索未修改的数据。 撤销日志存在于撤消日志段中,该日志段包含在回滚段中。 回滚段位于系统表空间,临时表空间和撤消表空间中。
InnoDB支持128个回滚段,其中32个保留为临时表事务的non-redo回滚段。 每个更新临时表(不包括只读事务)的事务都被分配了两个回滚段,一个启用了redo的回滚段和一个non-redo回滚段。 只读事务只分配non-redo回滚段,因为只读事务只允许修改临时表。
这留下了96个可用回滚段,每个回滚段支持多达1023个并发数据修改事务,总共限制大约96K个并发数据修改事务。 96K限制假定事务不修改临时表。 如果所有数据修改事务也修改临时表,则总数限制约为32K个并发数据修改事务。 有关为临时表事务保留的回滚段的更多信息,请参见临时表撤消日志。
innodb_rollback_segments选项定义了InnoDB使用的回滚段的数量。
14.4.9 File-Per-Table 表空间
file-per-table 的表空间是一个单表表空间,它是在其自己的数据文件中创建的,而不是在系统表空间中创建的。 当启用innodb_file_per_table选项时(默认启用),将在每个文件表的表空间中创建表。 否则,InnoDB表将在系统表空间中创建。 每个每个文件表的表空间由一个.ibd数据文件表示,默认情况下该数据文件在数据库目录中创建。
file-per-table 表空间支持DYNAMIC和COMPRESSED行格式,支持诸如用于可变长度数据和表压缩的离页存储等功能。
14.4.10 一般表空间
使用CREATE TABLESPACE语法创建的共享InnoDB表空间。 常规表空间可以在MySQL数据目录之外创建,能够保存多个表,并支持所有行格式的表。
使用CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name或ALTER TABLE tbl_name TABLESPACE [=] tablespace_name语法将表添加到常规表空间中。
14.4.11 Undo 表空间
undo表空间包含一个或多个包含undo 日志的文件。 InnoDB使用的撤消表空间的数量由innodb_undo_tablespaces配置选项定义。
注意:
innodb_undo_tablespaces已被弃用,并将在未来版本中删除。
14.4.12 临时表空间
非压缩的,用户创建的临时表和磁盘内部临时表是在共享的临时表空间中创建的。 innodb_temp_data_file_path配置选项定义临时表空间数据文件的相对路径,名称,大小和属性。 如果没有为innodb_temp_data_file_path指定值,则缺省行为是在innodb_data_home_dir目录中创建名为ibtmp1的自动扩展数据文件,该文件略大于12MB。
压缩临时表是使用ROW_FORMAT = COMPRESSED属性创建的临时表,它们是在临时文件目录中在 file-per-table 表空间被创建
临时表空间在正常关闭或中止初始化时被删除,并在每次启动服务器时重新创建。 临时表空间在创建时接收动态生成的空间ID。 如果无法创建临时表空间,则启动将被拒绝。 如果服务器意外停止,则不会删除临时表空间。 在这种情况下,数据库管理员可以手动删除临时表空间或重新启动服务器,该服务器会自动删除并重新创建临时表空间。
临时表空间不能驻留在原始设备上。
INFORMATION_SCHEMA.FILES提供有关InnoDB临时表空间的元数据。 发出与此类似的查询来查看临时表空间元数据:
mysql> SELECT * FROM INFORMATION_SCHEMA.FILES WHERETABLESPACE_NAME='innodb_temporary'\G
INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO提供有关在InnoDB实例中当前处于活动状态的用户创建的临时表的元数据。
管理临时表空间数据文件大小
默认情况下,临时表空间数据文件是自动扩展的,并根据需要增加大小以适应磁盘上的临时表。 例如,如果某个操作创建了一个大小为20 MB的临时表,则临时表空间数据文件(在创建时默认大小为12 MB)会扩展以容纳它。 当删除临时表时,释放的空间可以重新用于新的临时表,但数据文件保持扩展大小。
在使用大型临时表或广泛使用临时表的环境中,自动扩展临时表空间数据文件可能会变大。 长时间运行的使用临时表的查询也可能导致大型数据文件。
要确定临时表空间数据文件是否自动扩展,请检查innodb_temp_data_file_path设置:
mysql> SELECT @@innodb_temp_data_file_path;
+------------------------------+
| @@innodb_temp_data_file_path |
+------------------------------+
| ibtmp1:12M:autoextend |
+------------------------------+
要检查临时表空间数据文件的大小,请使用与此类似的查询来查询INFORMATION_SCHEMA.FILES表:
mysql> SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, INITIAL_SIZE,TOTAL_EXTENTS*EXTENT_SIZE AS TotalSizeBytes, DATA_FREE, MAXIMUM_SIZEFROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME ='innodb_temporary'\G

TotalSizeBytes值报告临时表空间数据文件的当前大小。
或者,您可以检查操作系统上的临时表空间数据文件大小。 缺省情况下,临时表空间数据文件位于由innodb_temp_data_file_path配置选项定义的目录中。 如果未明确指定此选项的值,则会在innodb_data_home_dir中创建名为ibtmp1的临时表空间数据文件,如果未指定,该文件将默认为MySQL数据目录。
要回收临时表空间数据文件占用的磁盘空间,可以重新启动MySQL服务器。 重新启动服务器将根据innodb_temp_data_file_path定义的属性删除并重新创建临时表空间数据文件。
要防止临时数据文件变得过大,可以配置innodb_temp_data_file_path选项以指定最大文件大小。 例如:
[mysqld] innodb_temp_data_file_path=ibtmp1:12M:autoextend:max:500M
当数据文件达到最大大小时,查询将失败,并显示表已满的错误。 配置innodb_temp_data_file_path需要重新启动服务器。
或者,您可以配置default_tmp_storage_engine和internal_tmp_disk_storage_engine选项,它们分别定义用于用户创建的和磁盘上的内部临时表的存储引擎。 这两个选项默认设置为InnoDB。 MyISAM存储引擎为每个临时表使用单独的文件,临时表被删除时删除该文件。
临时表的Undo logs
临时表撤消日志驻留在临时表空间中,用于临时表和相关对象。 临时表撤消日志不会被redo 记录,因为它们不是崩溃恢复所必需的。 它们仅用于服务器运行时的回滚。 这种特殊类型的撤消日志通过避免redo日志I / O来提高性能。 对于修改临时表和相关对象的事务,将为临时表撤消日志保留32个回滚段。
14.4.13 redo log
与任何其他ACID兼容的数据库引擎一样,InnoDB在提交之前刷新事务的重做日志。 InnoDB使用组提交功能将多个这样的刷新请求组合在一起,以避免每次提交刷新一次。 通过组提交,InnoDB向日志文件发出一次写入操作,以便为大约同时提交的多个用户事务执行提交操作,从而显着提高吞吐量。
重做日志是在崩溃恢复期间使用的基于磁盘的数据结构,用于纠正由不完整事务写入的数据。 在正常操作期间,重做日志对请求进行编码,以更改由SQL语句或低级API调用产生的InnoDB表数据。 在意外关闭之前没有完成更新数据文件的修改会在初始化期间以及接受连接之前自动重用。
默认情况下,重做日志在物理上表现为一组名为ib_logfile0和ib_logfile1的文件。 MySQL以循环方式写入重做日志文件。 重做日志中的数据按受影响的记录进行编码; 这些数据统称为redo。 数据通过重做日志的过程由不断增加的LSN值表示。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3118077/ ,如需转载,请注明出处,否则将追究法律责任。