【MySQL技术内幕】3.6-InnoDB存储引擎文件

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【MySQL技术内幕】3.6-InnoDB存储引擎文件

之前介绍的文件都是 MySQL数据库本身的文件,和存储引擎无关。除了这些文件外,每个表存储引擎还有其自己独有的文件。本节将具体介绍与 InnoDB存储引擎密切相关的文件,这些文件包括重做日志文件、表空间文件。

1、表空间文件

InnoDB采用将存储的数据按表空间(tablespace)进行存放的设计。在默认配置下会有一个初始大小为10MB,名为 ibdata1的文件。该文件就是默认的表空间文件(tablespace file),用户可以通过参数 innodb_data_file_path对其进行设置,格式如下

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

用户可以通过多个文件组成一个表空间,同时制定文件的属性,如:

[mysqld]
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M:autoextend

这里将/db/ibdata1和/dr2/db/ibdata2两个文件用来组成表空间。若这两个文件位于不同的磁盘上,磁盘的负载可能被平均,因此可以提高数据库的整体性能。同时,两个文件的文件名后都跟了属性,表示文件 idbdata1的大小为2000MB,文件 ibdata2的大小为2000MB,如果用完了这2000MB,该文件可以自动增长(autoextend)设置 innodb_data_file_path参数后,所有基于 InnoDB存储引擎的表的数据都会记录到该共享表空间中。若设置了参数 innodb_file_per_table,则用户可以将每个基于InnoDB存储引擎的表产生一个独立表空间。独立表空间的命名规则为:表名.ibd。通过这样的方式,用户不用将所有数据都存放于默认的表空间中。下面这台 MySQL数据库服务器设置了 innodb_file_per_table,故可以观察到:

mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)
 
mysql> system sudo ls /usr/local/mysql/data/mysql
columns_priv.MYD    event.MYI     help_category.frm   innodb_table_stats.frm    procs_priv.MYD      slave_master_info.frm   tables_priv.MYI     time_zone_transition_type.frm
columns_priv.MYI    event.frm     help_category.ibd   innodb_table_stats.ibd    procs_priv.MYI      slave_master_info.ibd   tables_priv.frm     time_zone_transition_type.ibd
columns_priv.frm    func.MYD      help_keyword.frm    ndb_binlog_index.MYD    procs_priv.frm      slave_relay_log_info.frm  time_zone.frm     user.MYD
db.MYD        func.MYI      help_keyword.ibd    ndb_binlog_index.MYI    proxies_priv.MYD    slave_relay_log_info.ibd  time_zone.ibd     user.MYI
db.MYI        func.frm      help_relation.frm   ndb_binlog_index.frm    proxies_priv.MYI    slave_worker_info.frm   time_zone_leap_second.frm user.frm
db.frm        general_log.CSM     help_relation.ibd   plugin.frm      proxies_priv.frm    slave_worker_info.ibd   time_zone_leap_second.ibd
db.opt        general_log.CSV     help_topic.frm      plugin.ibd      server_cost.frm     slow_log.CSM      time_zone_name.frm
engine_cost.frm     general_log.frm     help_topic.ibd      proc.MYD      server_cost.ibd     slow_log.CSV      time_zone_name.ibd
engine_cost.ibd     gtid_executed.frm   innodb_index_stats.frm    proc.MYI      servers.frm     slow_log.frm      time_zone_transition.frm
event.MYD     gtid_executed.ibd   innodb_index_stats.ibd    proc.frm      servers.ibd     tables_priv.MYD     time_zone_transition.ibd

由于设置参数 innodb_file_per_table=ON,因此产生了单独的.ibd独立表空间文件。需要注意的是,这些单独的表空间文件仅存储该表的数据、索引和插入缓冲 BITMAP等信息,其余信息还是存放在默认的表空间中。图显示了 InnoDB存储引擎对于文件的存储方式:

image.png

2、重做日志文件

在默认情况下,在 InnoDB存储引擎的数据目录下会有两个名为 ib_logfile0和ib_logfile1的文件。在 MySQL官方手册中将其称为 InnoDB存储引擎的日志文件,不过更准确的定义应该是重做日志文件(redo log file)。为什么强调是重做日志文件呢?因为重做日志文件对于 InnoDB存储引擎至关重要,它们记录了对于 InnoDB存储引擎的事务日志。

当实例或介质失败(media failure)时,重做日志文件就能派上用场。例如,数据库由于所在主机掉电导致实例失败, InnoDB存储引擎会使用重做日志恢复到掉电前的时刻,以此来保证数据的完整性。

每个 InnoDB存储引擎至少有1个重做日志文件组( group),每个文件组下至少有2个重做日志文件,如默认的 ib_logfile0和 ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB存储引擎先写重做日志文件,当达到文件的最后时会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。

下图显示了一个拥有3个重做日志文件的重做日志文件组。

image.png

下列参数影响着重做日志文件的属性:

  • innodb_log_file_size
  • innodb_log_files_in_group
  • innodb_mirrored_log_groups
  • innodb_log_group_home_dir

参数 innodb_log_file_size指定每个重做日志文件的大小。在 InnoDB1.2.x版本之前,重做日志文件总的大小不得大于等于4GB,而1.2.x版本将该限制扩大为了512GB参数 innodb_log_files_in_group指定了日志文件组中重做日志文件的数量,默认为2。

参数innodb _mirrored_log_groups指定了日志镜像文件组的数量,默认为1,表示只有一个日志文件组,没有镜像。若磁盘本身已经做了高可用的方案,如磁盘阵列,那么可以不开启重做日志镜像的功能。最后,参数 innodb_log_ group_home_dir指定了日志文件组所在路径,默认为./,表示在 MySQL数据库的数据目录下。

重做日志文件的大小设置对于 InnoDB存储引擎的性能有着非常大的影响。一方面重做日志文件不能设置得太大,如果设置得很大,在恢复时可能需要很长的时间方面又不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件。

此外,重做日志文件太小会导致频繁地发生 async checkpoint,导致性能的抖动。例如,用户可能会在错误日志中看到如下警告信息: image.png

上面错误集中在 InnoDB: ERROR the age of the last checkpoint is 9433645, InnoDB which exceeds the log group capacity 9433498。这是因为重做日志有一个 capacity变量,该值代表了最后的检查点不能超过这个阈值,如果超过则必须将缓冲池( innodb buffer pool)中脏页列表(flush list)中的部分脏数据页写回磁盘,这时会导致用户线程的阻塞。

也许有人会问,既然同样是记录事务日志,和之前介绍的二进制日志有什么区别?

首先,二进制日志会记录所有与 MySQL数据库有关的日志记录,包括 InnoDB、MyISAM、Heap等其他存储引擎的日志。而 InnoDB存储引擎的重做日志只记录有关该存储引擎本身的事务日志。

其次,记录的内容不同,无论用户将二进制日志文件记录的格式设为 STATEMENT还是ROW,又或者是 MIXED,其记录的都是关于一个事务的具体操作内容,即该日志是逻辑日志。而 InnoDB存储引擎的重做日志文件记录的是关于每个页(Page)的更改的物理情况。

此外,写入的时间也不同,二进制日志文件仅在事务提交前进行提交,即只写磁盘一次,不论这时该事务多大。而在事务进行的过程中,却不断有重做日志条目(redo entry)被写入到重做日志文件中。

在InnoDB存储引擎中,对于各种不同的操作有着不同的重做日志格式。到 InnoDB 1.2.x版本为止,总共定义了51种重做日志类型。虽然各种重做日志的类型不同,但是它们有着基本的格式,下图显示了重做日志条目的结构:

image.png

从表可以看到重做日志条目是由4个部分组成:

  • redo_log_type占用1字节,表示重做日志的类型
  • space表示表空间的ID,但采用压缩的方式,因此占用的空间可能小于4字节
  • page_no表示页的偏移量,同样采用压缩的方式
  • redo_log_body表示每个重做日志的数据部分,恢复时需要调用相应的函数进行解析

写人重做日志文件的操作不是直接写,而是先写入一个重做日志缓冲( redo log buffer)中,然后按照一定的条件顺序地写入日志文件。下图很好地诠释了重做日志的写人过程。

image.png

从重做日志缓冲往磁盘写入时,是按512个字节,也就是一个扇区的大小进行写入。因为扇区是写人的最小单位,因此可以保证写入必定是成功的。因此在重做日志的写入过程中不需要有 doublewrite。

前面提到了从日志缓冲写入磁盘上的重做日志文件是按一定条件进行的,那这些条件有哪些呢?在主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件中,不论事务是否已经提交。另一个触发写磁盘的过程是由参数 innodb_flush_log_at_trx_commit控制,表示在提交( commit)操作时,处理重做日志的方式。

参数 innodb_flush_log_at_trx_commit的有效值有0、1、2。0代表当提事务时够并不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新。1和2不同的地方在于:1表示在执行comm时将重做日志缓冲同步写到磁盘,即伴有 fsync的调用。2表示将重做日志异步写到磁盘,即写到文件系统的缓存中。因此不能完全保证在执行 commit时肯定会写入重做日志文件,只是有这个动作发生。

因此为了保证事务的ACID中的持久性,必须将 innodb_flush_log_ at_trx_commit设置为1,也就是每当有事务提交时,就必须确保事务都已经写入重做日志文件。那么当数据库因为意外发生宕机时,可以通过重做日志文件恢复,并保证可以恢复已经提交的事务。而将重做日志文件设置为0或2,都有可能发生恢复时部分事务的丢失。不同之处在于,设置为2时,当 MySQL数据库发生宕机而操作系统及服务器并没有发生宕机时,由于此时未写入磁盘的事务日志保存在文件系统缓存中,当恢复时同样能保证数据不丢失。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
108 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
6天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的表空间
InnoDB是MySQL默认的存储引擎,主要由存储结构、内存结构和线程结构组成。其存储结构分为逻辑和物理两部分,逻辑存储结构包括表空间、段、区和页。表空间是InnoDB逻辑结构的最高层,所有数据都存放在其中。默认情况下,InnoDB有一个共享表空间ibdata1,用于存放撤销信息、系统事务信息等。启用参数`innodb_file_per_table`后,每张表的数据可以单独存放在一个表空间内,但撤销信息等仍存放在共享表空间中。
|
6天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的段、区和页
MySQL的InnoDB存储引擎逻辑存储结构与Oracle相似,包括表空间、段、区和页。表空间由段和页组成,段包括数据段、索引段等。区是1MB的连续空间,页是16KB的最小物理存储单位。InnoDB是面向行的存储引擎,每个页最多可存放7992行记录。
|
6天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL的InnoDB存储引擎
InnoDB是MySQL的默认存储引擎,广泛应用于互联网公司。它支持事务、行级锁、外键和高效处理大量数据。InnoDB的主要特性包括解决不可重复读和幻读问题、高并发度、B+树索引等。其存储结构分为逻辑和物理两部分,内存结构类似Oracle的SGA和PGA,线程结构包括主线程、I/O线程和其他辅助线程。
【赵渝强老师】MySQL的InnoDB存储引擎
|
7天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
21 4
|
5天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
17 1
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引
|
14天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
74 1
|
16天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
59 2
|
19天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
77 4