MySQL相关文件——Innodb存储引擎文件

  • Post author:
  • Post category:mysql


上面说的都是MySQL本身的文件,与存储引擎无关。除了这些文件外,每个表存储引擎都还有自己独有的文件:

  • 表空间文件

  • 重做日志文件



1. 表空间文件

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

查看参数对应值:

mysql> show variables like 'innodb_data_file_path';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
+-----------------------+------------------------+
1 row in set (0.01 sec)

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

MySQL表空间的扩容:(当前定义的表空间或默认表空间是不能改变的,否则启动失败,但是可以添加额外的表空间,ibdataN序列根据当前的数量递增)

1. 查看当前数据库系统表空间大小设置:
 mysql> show variables like 'innodb_data_file_path';
+-----------------------+-----------------------+
| Variable_name         | Value                 |
+-----------------------+-----------------------+
| innodb_data_file_path | ibdata1:1G:autoextend |
+-----------------------+-----------------------+
1 row in set (0.02 sec)

2. 关闭数据库,修改配置文件:
  mysql> shutdown
  [root@mysql8 mysql_3306]# vim my_3306.cnf 
  [root@mysql8 mysql_3306]# cat my_3306.cnf | grep innodb_data_file_path
innodb_data_file_path = ibdata1:1G;ibdata2:200M:autoextend

3. 启动数据库后查看参数值:
mysql> show variables like 'innodb_data_file_path';
+-----------------------+------------------------------------+
| Variable_name         | Value                              |
+-----------------------+------------------------------------+
| innodb_data_file_path | ibdata1:1G;ibdata2:200M:autoextend |
+-----------------------+------------------------------------+
1 row in set (0.00 sec)

4. 查看相应的数据文件目录:
[root@mysql8 data]# ls ibdata*
ibdata1  ibdata2 

我这里将数据文件目录下ibdata1,ibdata2用来组成表空间。如果这两个文件在不同磁盘上,磁盘的负载可能会被平均,因此可以提高数据库的整体性能。

ibdata1:1G;ibdata2:200M:autoextend

这两个文件的文件名后面都跟了属性,表示文件ibdata1的大小为2G,文件ibdata2大小为200M,如果这200M用完可以自动扩展。

设置innodb_data_file_path,所有基于Innodb存储引擎的表的数据都会记录到该共享表空间里面。如果设置参数innodb_file_per_table,则用户可以将每个基于Innodb存储引擎的表产生一个独立表空间。

独立表空间的命名规则为:

表名.ibd

mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.01 sec)

mysql> create table test3(id int,name char(20));
Query OK, 0 rows affected (0.11 sec) 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfSf48FH-1604373951421)(https://secure-static.wolai.com/static/jELHUqEQHpxEjRBgiBH1on/image.png)]

因为设置了参数innodb_file_per_table=ON,因此会产生单独的.ibd表空间文件。但是这些单独的表空间文件只会存储该表的数据,索引和插入缓冲等信息,其他信息还是存放在默认的表空间中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KV7XyPJE-1604373951423)(https://secure-static.wolai.com/static/emk9tspzanGg75fd7Eg5yn/image.png)]



2. 重做日志文件

默认情况,在Innodb存储引擎的数据目录下会有名字为ib_logfile0,ib_logfile1…类似的文件。如下所示:

[root@mysql8 data]# ll *logfile*
-rw-r----- 1 mysql mysql 2147483648 Oct 28 16:18 ib_logfile0
-rw-r----- 1 mysql mysql 2147483648 Aug  4 11:04 ib_logfile1
-rw-r----- 1 mysql mysql 2147483648 Aug  4 11:04 ib_logfile2

在MySQL的官方手册中称之为Innodb存储引擎的日志文件,实际上就是重做日志文件(redo log file),这个文件记录了对于Innodb存储引擎的事务日志。

当实例或者介质失败时(media failure)重做日志就会发挥作用,InnoDB存储引擎可以根据重做日志将数据库恢复到异常终止前的时刻,来保证数据的完整性。

每个Innodb存储引擎至少有一个重做日志组(group),每个文件组下至少有两个重做日志文件,ib_logfile0和ib_logfile1就是一个日志组。为了提高可靠性,用户可以设置多个镜像日志组(mirrored log groups),将不同的文件放在不同的磁盘上,以此来提高日志的可用性。


日志组中的每个重做日志文件大小一致,并以循环写入的方式进行,Innodb存储引擎先写日志文件1,当达到文件最后时会切换到日志文件2,当重做日志2写满再切回到重做日志文件1

,其顺序如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBjSIxcx-1604373951426)(https://secure-static.wolai.com/static/iFPy6fkg7BytLuzc2FxVVP/image.png)]

和重做日志文件有关的参数:

  • innodb_log_file_size

  • innodb_log_files_in_group

  • innodb_mirrored_log_group

  • innodb_log_group_home_dir

参数innodb_log_file_size指定了每个重做日志文件的大小。在Innodb1.2.x版本前,重做日志文件大小不能超过4G,在1.2.x以后将这个限制扩大为512G。

mysql> show variables like 'innodb_log_file_size';
+----------------------+------------+
| Variable_name        | Value      |
+----------------------+------------+
| innodb_log_file_size | 2147483648 |
+----------------------+------------+
1 row in set (0.01 sec)

参数innodb_log_files_in_group指定了日志文件组中重做日志文件的数量,默认为2。

mysql> show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 3     |
+---------------------------+-------+
1 row in set (0.00 sec)

参数innodb_mirrored_log_groups指定了日志镜像文件组的数量,默认为1,表示只有一个日志文件组,没有镜像。建议生产环境开启镜像文件组,当然如果磁盘本身具有高可用方案,比如磁盘阵列,那么可以不开启。

参数innodb_log_group_home_dir指定了日志文件的所在路径,默认为./,表示存放在MySQL数据库的数据目录下。

下述为MySQL8的重做日志组配置:

mysql> show variables like 'innodb%log%';
+------------------------------------+------------+
| Variable_name                      | Value      |
+------------------------------------+------------+
| innodb_api_enable_binlog           | OFF        |
| innodb_flush_log_at_timeout        | 1          |
| innodb_flush_log_at_trx_commit     | 1          |
| innodb_log_buffer_size             | 33554432   |
| innodb_log_checksums               | ON         |
| innodb_log_compressed_pages        | ON         |
| innodb_log_file_size               | 2147483648 |
| innodb_log_files_in_group          | 3          |
| innodb_log_group_home_dir          | ./         |
| innodb_log_spin_cpu_abs_lwm        | 80         |
| innodb_log_spin_cpu_pct_hwm        | 50         |
| innodb_log_wait_for_flush_spin_hwm | 400        |
| innodb_log_write_ahead_size        | 8192       |
| innodb_max_undo_log_size           | 4294967296 |
| innodb_online_alter_log_max_size   | 4294967296 |
| innodb_print_ddl_logs              | ON         |
| innodb_redo_log_encrypt            | OFF        |
| innodb_undo_log_encrypt            | OFF        |
| innodb_undo_log_truncate           | ON         |
+------------------------------------+------------+
19 rows in set (0.01 sec)

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

重做日志文件太小会导致频繁发生async checkpoint

,因而导致性能的抖动。


与二进制日志的区别:

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

  2. 除此之外,二者记录的内容也是不同的,无论用户将二进制日志的内容设置成什么格式,其记录都是关于一个事务的具体操作内容,也就是说这个日志是一个逻辑日志。而InnoDB存储引擎的重做日志文件记录的是关于每个页(Page)的更改的物理情况。

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

在InnoDB存储引擎中,对于各种不同的操作有着不同重做日志格式。到InnoDB1.2.x版本为止,总共定义了51种重做日志类型。虽然各种重做日志的类型不同,但是他们有着基本的格式如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L0RepebF-1604373951429)(https://secure-static.wolai.com/static/x8vHuSoMGxiPWNddKn2N7q/image.png)]

  • redo_log_type 占用1字节,表示重做日志的类型。

  • space表示表空间ID,但采用压缩的方式,因此占用的空间可能小于4字节

  • page_no 表示页的偏移量,同样采用压缩的方式

  • redo_log_body 表示每个重做日志的数据部分,恢复时需要调用相应的函数进行解析


写入重做日志文件的流程

写入重做日志文件的操作不是直接写,而是先写入到日志缓冲(redo log buffer)中,然后按照一定顺序写入到日志文件中。如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oavTf2Ly-1604373951433)(https://secure-static.wolai.com/static/9cMLqbTPUDfPqgou6ZJ4Fm/image.png)]

为什么重做日志写入不需要二次写

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

关于重做日志缓冲写入到重做日志中的触发条件

1)主线程master thread每秒都会将重做日志缓冲写入到重做日志文件中。

2)参数

innodb_flush_log_at_trx_commit

,该参数表示再提交commit操作的时候,数据库如何处理重做日志的方式。

该参数有效值为:0、1、2

0 代表当前在提交事务的时候,不会将事务的重做日志写入到磁盘上的重做日志文件,而是等待主线程每秒的刷新。

1代表在执行commit操作的时候,将重做日志缓冲同步写到磁盘,即伴有fsync的调用。

2表示将重做日志异步写到磁盘中,即写到文件系统的缓存中。·因此不能保证再执行commit的时候一定伴随写入到重做日志文件中,只是一定会有这个动作发生。


如果要保证事务中的持久性,就一定要将参数


innodb_flush_log_at_trx_commit


设置为1,这样每当有事务提交的时候,都必须保证事务都已经写入到重做日志文件。这样即使数据库意外宕机,也可以通过重做日志文件进行恢复,并且保证可以恢复已经提交的事务。

将重做日志文件设置为0或者2都有可能发生恢复时部分事务的丢失。不同之处在于设置为2时,当MySQL数据库发生宕机而操作系统及服务器并没有发生宕机时,由于此时未写入磁盘的事务日志保存在文件系统缓存中,当恢复时同样能保证数据不丢失。



版权声明:本文为qq_43250333原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。