【InnoDB磁盘结构1】系统表空间,独立表空间,双写缓冲区
目录
一. 系统表空间 - System Tablespace
1.1.系统表空间的作用?
1.2.系统表空间文件保存在哪里?
1.3.系统表空间都有哪些可以配置的选项?
二. 独立表空间 - File-Per-Table Tablespace
2.1.独立表空间的作用?
2.2. 独立表空间文件保存在哪里?
2.3 每个表都对应一个独立表空间吗?
2.4 独立表空间的优点和缺点?
三. 双写缓冲区 (Doublewrite Buffer)
3.1.双写缓冲区的作用
3.2. 双写缓冲区中的数据保存在哪里?
3.3.如何配置双写缓冲区?
InnoDB存储引擎包含哪些磁盘结构?
我们可以去官网看看:MySQL :: MySQL 8.0 Reference Manual :: 17.4 InnoDB Architecture
除了内存结构之外,InnoDB存储引擎还有磁盘结构这么一大块
磁盘结构
-
系统表空间 (System Tablespace)——保存的是系统的一些数据(系统变量等),注意那个ibdata1,就是我们的系统表空间名,里面的Change Buffer和内存结构的Change Buffer是不是有点关系呢?
-
独立表空间 (File-Per-Table Tablespaces)——我们看到.ibd文件,我们在使用innoDB存储引擎每创建一个表,就会生成一个.ibd文件,这个.ibd文件就是独立表空间文件
-
通用表空间 (General Tablespaces)——这个和独立表空间有点类似,只不过一个通用表空间文件可以存储多个表的数据。
-
临时表空间 (Temporary Tablespaces)——一组文件。
-
撤销表空间 (Undo Tablespaces)——保存undo日志
-
重做日志 (Redo Log) ——崩溃恢复
-
双写缓冲区 (Doublewrite Buffer) ——保证数据安全
关于磁盘结构的信息,我们可以去官网好好看看:MySQL :: MySQL 8.0 Reference Manual :: 17.6 InnoDB On-Disk Structures
什么是表空间?什么是表空间文件?
- 表空间可以理解为MYSQL为了管理数据而设计的一种数据结构,主要描述的对结构的定义
- 表空间文件是对定义的具体实现,以文件的形式存在于磁盘上
以后我们说的表空间指的就是表空间文件
InnoDB存储引擎的表空间包括:系统表空间、独立表空间、通用表空间、临时表空间和撤销表空间
本节重点介绍不同表空间的作用
关于表空间呢?我们可以去官网看看:MySQL :: MySQL 8.0 Reference Manual :: 17.6.3 Tablespaces
一. 系统表空间 - System Tablespace
系统表空间在innoDB存储引擎架构的磁盘结构里面
大家如果想要了解系统表空间的官方文档,可以去:MySQL :: MySQL 8.0 Reference Manual :: 17.6.3.1 The System Tablespace
1.1.系统表空间的作用?
- 系统表空间存储了 MySQL 中所有系统表(下面4个)的数据,也包括数据字典;
- 系统表空间也是变更缓冲区的存储区域,当数据库服务器关闭时,没有合并到缓冲池的二级索引修改操作被保存到系统表空间;
- 在以前的版本中,系统表空间也包含双写缓冲区,从 MySQL 8.0.20 开始,双写缓冲区从系统表空间中移到单独的文件中。
我知道上面这些远远不能满足你们的胃口,我们接下来再详细看看
我们来用最形象的方式解释系统表空间的作用,就像描述一个城市的「核心基础设施中心」:
想象你管理一座庞大的现代化城市(MySQL数据库):
-
城市的“户籍档案中心”(数据字典与系统表)
-
系统表空间最核心的作用,就是存储整个城市的核心档案资料。这包括:
-
所有建筑物的登记信息: 每栋楼叫什么(表名)、有几层(表结构)、每层住哪些人(列信息)、楼和楼之间有什么关系(外键约束)——这就是 数据字典(Data Dictionary)。
-
城市管理法规: 用户权限设置、字符集规则、存储引擎配置等系统级元数据。
-
-
如果把每个数据库表看作一栋独立的建筑(独立表空间),那么系统表空间就是存放整个城市规划蓝图和产权登记册的地方。没有它,城市管理者(MySQL服务器)就不知道有哪些建筑、谁有权进入、建筑之间如何联系。它是数据库自我认知的基石。
-
-
“施工变更暂存区”(变更缓冲区的持久化存储)
-
之前提到过变更缓冲区(Change Buffer),它像个“施工队待办事项本”,记录了对二级索引(如按姓名排序的目录)的修改指令(如“在A区插入张三”)。
-
系统表空间是这个“施工队待办事项本”的保险柜。当城市遇到突发情况需要关闭(数据库服务器关闭)时,施工队(内存中的Change Buffer)还没来得及去各个目录柜(二级索引页)完成所有修改。这时,他们会把“待办事项本”安全地锁进系统表空间这个保险柜里保存起来。
-
等城市重新开放(数据库重启),施工队第一件事就是打开保险柜(系统表空间),拿出“待办事项本”,继续完成那些未完成的目录修改(将Change Buffer中的操作合并到缓冲池)。这确保了即使在意外关闭后,所有已提交的“目录修改承诺”最终都会兑现,数据不会丢失或错乱。
-
-
曾经的“双重安全保障库”(双写缓冲区 - 历史角色)
-
在城市的建设中,防止“豆腐渣工程”很重要。以前,系统表空间还兼任一个关键的安全角色——双写缓冲区(Doublewrite Buffer) 的存储地。
-
它的作用:当施工队(InnoDB)要新建或翻修一栋楼(数据页),在把最终成果正式写到新地址前,会先把设计图纸和建材完整复制一份存到系统表空间这个“安全样板库”里。万一正式施工时遇到地震断电(部分写失效),就可以用这里保存的完整备份快速修复损坏的楼,保证建筑结构绝对可靠(数据页完整性)。
-
更新: 从MySQL 8.0.20开始,这个“安全样板库”(双写缓冲区)搬出了系统表空间,有了自己独立的文件(如
#ib_16384_0.dblwr
),更专业高效。但了解这个历史角色有助于理解系统表空间曾经的综合性。
-
-
“老城区”的遗留功能(可选存放用户表数据(跟下面的独立表空间有关哦))
-
最新的MySQL版本中,
innodb_file_per_table
默认是ON的,也就是说系统默认启用独立表空间(File-Per-Table 表空间包含单个InnoDB表的数据和索引,默认情况下每张表都对应一个独立表空间数据文件,便于维护),再说的直白一点,每个表都有1个.ibd文件和它对应,这个表的数据都存在这个.ibd文件里面(也就是我们下面的独立表空间文件) -
在早期MySQL版本,或者当管理员特意关闭了“独立集装箱”模式(
innodb_file_per_table=OFF
)时,普通用户表的数据和索引也会被直接存放在系统表空间这个大仓库里,就像老城区所有房子都挤在一个大院里。 -
强烈不推荐: 这样做会让“核心档案”和“普通住户”混居,导致:
-
空间无法回收: 即使拆掉一栋楼(
DROP TABLE
),它占的地盘也腾不出来给操作系统,只能在“大院”里闲置(空间膨胀且只增不减)。 -
性能与管理瓶颈: 所有操作都挤在同一个大文件,I/O竞争激烈,备份恢复也不灵活。
-
-
现代最佳实践是开启独立表空间,让普通住户(用户表)搬到自己的专属区域(
.ibd
文件),系统表空间专心做它的“核心管理中心”。
-
为什么系统表空间如此关键且不可替代?
-
唯一性: 一个MySQL实例通常只有一个系统表空间(虽然可由多个文件组成)。它是整个数据库的“神经中枢”。
-
启动基石: MySQL服务器启动时,第一个访问的就是系统表空间。它要从中读取数据字典等信息,才能知道有哪些数据库、表、用户,以及如何访问它们。没有它,数据库无法“认识自己”。
-
事务安全基石: 它确保了即使发生崩溃,那些已提交但未完全落地的“目录修改”(Change Buffer内容)不会丢失,维护了数据的一致性。
-
集中管理核心元数据: 数据字典等核心信息必须集中、可靠地存储,系统表空间就是这个中心仓库。
1.2.系统表空间文件保存在哪里?
系统表空间可以对应一个或多个数据文件,默认情况下,MySQL 在 data 目录中创建一个系统表空间数据文件 ibdata1。
系统表空间数据文件的大小和数量由 innode_data_file_path 启动选项定义。
1.3.系统表空间都有哪些可以配置的选项?
- 可以通过 innodb_data_file_path 选项定义,如果没有指定 innodb_data_file_path 的值,则默认创建一个大小可以自动扩展的数据文件,文件名为 ibdata1, 初始大小 12MB。
我们可以去官网看看:
SHOW VARIABLES LIKE 'innodb_data_file_path';
数据文件命名规范的完整语法包括文件名、文件大小、自动扩展属性和max属性:
file_name:file_size[:autoextend[:max:max_file_size]]
通过在 file_size 值后面指定单位 K、M 或 G 来设置文件大小,单位为 千字节、兆字节 或 千兆字节。如果以 K 为单位指定文件大小,应设置为1024的倍数。否则,千字节值四舍五入到最接近的兆字节(MB),且文件大小至少为 12MB。
- 指定多个数据文件可以使用分号;分隔。例如:
# mysqld节点
[mysqld]
# 文件1名称为:ibdata1 大小为50M
# 文件2名称为:ibdata2 大小为50M,自动扩容
innode_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
autoextend 和 max 属性只能用于最后指定的数据文件。也就是说,下面这种写法是不行的。
# mysqld节点 [mysqld] # 文件1名称为:ibdata1 大小为50M # 文件2名称为:ibdata2 大小为50M,自动扩容 innode_data_file_path=ibdata2:50M:autoextend;ibdata1:50M
当指定 autoextend 属性时,数据文件的大小会根据需要自动扩容,默认每次增加 64MB。
可以通过系统变量 innode_autoextend_increment 控制增量的大小;
如果要指定数据文件的最大容量,在 autoextend 后面指定 max 属性。
注意:只有在明确了解限制磁盘使用的情况下才使用 max 属性。(所以,我们一般是不配置max的)
下面的配置允许 ibdata1 扩展到 500MB:
# mysqld节点
[mysqld]
# 初始大小12M,允许自动扩容,最大可以扩容到500M
innode_data_file_path=ibdata1:12M:autoextend:max:500M
- 系统表空间文件默认创建在 data 目录下。如果指定其他的目录,使用 innode_data_home_dir 选项。
例如,要在名为 myibdata 的目录下创建一个系统表空间数据文件,可以使用如下配置:
# mysqld节点
[mysqld]
# 指定innodb数据目录
innode_data_home_dir = /myibdata/
# 配置系统表空间
innode_data_file_path=ibdata1:50M:autoextend
注意:
- 修改或指定自定义目录时,一定要检查或设置目标目录的权限,让MySQL可以进行读写操作,否则就会启动失败。
- 指定 innode_data_home_dir 时,必须以斜杠 / 结尾,InnoDB不会自动创建目录,所以在启动服务器之前要确保指定的目录已经存在,最终通过 innode_data_home_dir 指定的路径与数据文件名组合起来生成完整路径,如果 innode_data_home_dir 不指定,默认值为"./",即MySQL的数据目录。
如果 innode_data_file_path 指定一个绝对路径,则不会读取 innode_data_home_dir 的值,系统表空间文件根据指定的绝对路径创建,启动服务器之前必须确保指定的目录存在。
在添加新的数据文件时,不要指定现有的文件名,InnoDB在启动服务器时会创建并初始化新的数据文件。
修改系统表空间配置后什么时候生效?
在修改系统表空间配置时,先停止MySQL服务,修改完成后,再重新启动MySQL服务之后生效。
二. 独立表空间 - File-Per-Table Tablespace
先来看看独立表空间在磁盘结构的哪里吧!!
大家也可以去官网看看它的信息:MySQL :: MySQL 8.0 Reference Manual :: 17.6.3.2 File-Per-Table Tablespaces
2.1.独立表空间的作用?
File-Per-Table 表空间包含单个InnoDB表的数据和索引,默认情况下每张表都对应一个表空间数据文件,便于维护,所以称为 File-Per-Table Tablespace。
我们来举例描述一下,
想象一下:你管理着一个巨大的仓库(数据库),里面存放着成千上万个不同的货物箱子(数据表)。
-
最初的做法(系统表空间时代): 所有货物箱子都堆放在同一个超级大的中央仓库区(系统表空间文件
ibdata1
)。管理员(MySQL)用一个总账本记录哪个箱子放在这个大仓库的哪个角落。 -
痛点出现了:
-
扔箱子难回收空间: 如果你想彻底扔掉一个旧箱子(
DROP TABLE
),管理员只是在总账本上把它标记为“废弃”,但那个箱子实际占用的地盘还在中央仓库里空着,没法立刻给新货物用。仓库空间越用越浪费(空间无法回收给操作系统)。 -
维护麻烦: 所有箱子混在一起,如果你想单独备份、移动或者优化某个特定箱子(表)的存放位置(比如放到更快的货架上),几乎不可能,因为它是整个大仓库的一部分。
-
风险集中: 万一中央仓库区(
ibdata1
文件)不小心损坏了一小块地方(比如硬盘坏道),可能波及到里面存放的很多个箱子(表),恢复起来很头疼。 -
格式限制: 你想给某些贵重箱子用更先进的压缩打包技术(
COMPRESSED
行格式)来省空间,但整个中央仓库区不支持这种高级打包方式。 -
容量天花板: 整个中央仓库区(系统表空间)最大只能建到 64TB,所有箱子共享这个空间。
-
独立表空间(File-Per-Table Tablespace)的解决方案:给每个箱子(表)配一个专属小仓库!
-
核心作用:让每个表拥有自己专属的“小仓库”文件(
.ibd
文件)。 这个文件只存放这个表的数据和索引,就像给每个货物箱子单独配了一个带锁的集装箱。 -
这样做的巨大好处:
-
空间回收立竿见影: 当你说“这个箱子我不要了!”(
DROP TABLE
),管理员直接把它的专属集装箱整个拆掉扔掉(删除.ibd
文件),它占用的地盘立刻还给仓库(操作系统),新货物马上就能用这块地。同样,清空箱子(TRUNCATE TABLE
)也是直接拆箱重建,速度飞快。 -
精细化管理:
-
灵活存放: 你可以把热门、经常要搬动的箱子(表),放到离仓库大门最近、搬运速度最快的货架(SSD 硬盘)上(通过
DATA DIRECTORY
指定路径)。冷门的大箱子可以放到便宜的大容量慢速货架(HDD 硬盘)上。 -
单独操作: 备份、恢复或者迁移某一个箱子变得极其简单——直接打包或移动它的专属集装箱文件(
.ibd
)就行,完全不影响其他箱子。 -
优化利器: 你可以为某些特殊形状或价值高的箱子(表)启用高级压缩打包技术(
COMPRESSED
或DYNAMIC
行格式),在它的专属集装箱里高效节省空间,这在中央大仓库是做不到的。
-
-
风险隔离: 万一某个专属集装箱(
.ibd
文件)不小心损坏了(比如文件系统错误),通常只影响这一个箱子(表)!其他箱子和核心的总账本(系统表空间)是安全的,修复或恢复这一个表相对容易很多。 -
突破容量限制: 每个专属集装箱(独立表空间)自己就能达到 64TB 大!想象一下,以前是所有箱子共享一个 64TB 的大仓库,现在每个箱子自己就能拥有一个 64TB 的超级集装箱,整个仓库(数据库)能容纳的货物总量大大增加。
-
维护透明: 管理员(InnoDB)管理这些专属集装箱非常直观。哪个箱子出问题、空间用多少,直接看对应的
.ibd
文件状态就行,一目了然。
-
当然,专属小仓库(独立表空间)也不是完美的:
-
可能浪费“小包装”: 如果一个箱子很小(比如只有几件货物),但它也独占了一个集装箱,集装箱里难免有些空余角落放不了其他东西(内部碎片)。箱子(表)越多,这种零碎的小空间可能累积起来也不少(空间浪费可能增加)。
-
管理员要记更多“钥匙”: 仓库管理员(操作系统)需要同时打开和管理成千上万个专属集装箱的门(文件描述符)。如果箱子(表)的数量极其庞大(比如几十万张表),可能会让管理员有点手忙脚乱(消耗更多文件句柄资源)。
-
扔箱子时可能要找找: 当你下令拆掉一个箱子(
DROP TABLE
)时,管理员需要去找到并清理它那个专属集装箱。如果箱子(表)特别多、集装箱散落在各处,这个“找箱子”的过程(文件系统操作)可能比在中央大仓库里划掉一个名字稍微慢一点点(对 DROP TABLE 性能的潜在影响)。 -
自动扩容规则固定: 专属集装箱(
.ibd
文件)需要变大时,每次固定增加 4MB 空间(增量固定),不像中央大仓库(系统表空间)可以通过参数 (innodb_autoextend_increment
) 灵活设置每次扩多大。
2.2. 独立表空间文件保存在哪里?
File-Per-Table 表空间在 数据目录/数据库名/目录下的 表名.ibd 表空间数据文件中创建。 .ibd 文件与表同名。
我们可以看看
create database db1;
这个时候我创建一个innodb表
use db1;
create table tb1(id int)engine=innodb;
看到了吧,这个tb1.ibd就是我们说的独立表空间文件。他和表同名
2.3 每个表都对应一个独立表空间吗?
- 不一定
默认每张表都对应一个表空间数据文件,innodb_file_per_table默认是on
但也可以通过系统变量 innodb_file_per_table={OFF|ON}] 控制开启或禁用是否为每张表生成一个独立表空间文件,如果禁用会在系统表空间中创建表;
可以在选项文件中指定 `innodb_file_per_table` 设置,也可以在运行时使用 **SET GLOBAL** 语句设置
- 选项文件中的mysqld节点
[mysqld]
innodb_file_per_table=ON
- 在运行时通过SET GLOBAL 设置
SET GLOBAL innodb_file_per_table=ON;
一般来说,我们 会将innodb_file_per_table设置为ON,也就是它的默认值。
2.4 独立表空间的优点和缺点?
1. 优点
使用 TRUNCATE 或 DROP 语句删除 File-Per-Table 表空间中的表后,磁盘空间会返回给操作系统,从而提高磁盘利用率,而共享表空间(比如:System Tablespace)则不会回收磁盘空间,而且在共享表空间中这些空间只能被InnoDB表重新使用;
执行时 TRUNCATE TABLE 时性能更好;
可以在其他目录或单独的存储设备上创建 File-Per-Table 表空间文件的数据文件,从而达到I/O优化、空间管理或备份的目的;
# 指定自定义存储目录子句,可以在外部目录中创建表
CREATE TABLE tl (cl INT PRIMARY KEY) DATA DIRECTORY = '/external/directory';
支持与 DYNAMIC 和 COMPRESSED 行格式,而系统表空间不支持;
发生数据损坏、备份、二进制日志不可用或MySQL服务器实例无法重新启动时提高成功恢复的机会;
单个表容量大小限制为 64TB,所以可以存储更多的数据,而共享表空间中的表的总容量为 64TB。
2. 缺点
每个表都可能有未使用的空间,这些空间只能由对应的表使用,如果管理不当,可能会导致空间浪费;
当每个表都有自己的数据文件,操作系统需要维护更多的文件描述符,如果表非常多,可能会影响性能;
可能会出现更多的磁盘碎片,会影响 DROP TABLE 表扫描性能;
innodb_autoextend_increment 系统变量定义了自动扩展共享表空间文件的增量大小,但对于 File-Per-Table 表空间文件不起作用,File-Per-Table 表空间文件始终自动扩展,初始大小根据表定义分配最小的空间,之后以 4MB 为增量进行扩容。
三. 双写缓冲区 (Doublewrite Buffer)
我们看看双写缓冲区在磁盘结构的哪里呢?
大家要是想了解他的一些信息,可以去官网看看:MySQL :: MySQL 8.0 Reference Manual :: 17.6.4 Doublewrite Buffer
3.1.双写缓冲区的作用
双写缓冲区是磁盘上的一个存储区域,当 InnoDB 将缓冲池中的数据页写入到磁盘上表空间数据文件之前,先将对应的页写到双写缓冲区;
如果在数据真正落盘的过程中出现了意外退出,比如操作系统、存储子系统崩溃或异常断电的情况,InnoDB 在崩溃恢复时可以从双写缓冲区中找到一份完好的页面本,执行过程如下图所示:
我们来深入浅出地解释 双写缓冲区(Doublewrite Buffer) 的核心作用,用最形象的比喻理解它的重要性:
想象场景: 你是一位银行的金库管理员(InnoDB存储引擎),负责把客户的金条(数据页)从临时保险柜(缓冲池/Buffer Pool)转移到永久金库(表空间数据文件)存放。
痛点:金条转移过程中的“摔碎”风险
-
每次转移金条(16KB数据页写入磁盘)时,你需要把整根金条一次性搬过去。但现实很残酷:
-
金库的保险箱(磁盘扇区)通常只能容纳 4KB 的小格子(磁盘的最小写入单位是扇区,常见4K)。
-
这就意味着,一根16KB的金条,需要拆分成 4个小块,依次放进保险箱的连续小格子里。
-
-
灾难性风险(部分写失效 / Partial Page Write):
-
如果在搬运过程中(比如放第3个小块时),突然发生地震、断电或搬运工手滑(操作系统崩溃、存储子系统故障、意外断电),导致写入操作中断。
-
后果:这根金条 只有一部分小块被成功写入 保险箱,另一部分丢失了。这根金条变得 支离破碎、无法辨认(数据页损坏)。
-
更糟的是,这个损坏的金条已经被标记为“已存入金库”(写入操作可能被记录到重做日志/Redo Log)。下次重启后,银行(数据库)根据记录去金库取这根金条时,发现它残缺不全,整个账目就乱套了!重做日志也无法修复这种物理层面的损坏。
-
双写缓冲区的妙招:金条的“安全中转站”
为了解决这个致命风险,银行(InnoDB)建立了一个 双写缓冲区(Doublewrite Buffer),它本质上是一个 专用的、高度安全的临时中转仓库。
金条转移的安全新流程:
-
第一步:先存“安全中转站”(双写缓冲区)
-
管理员(InnoDB)不会直接把金条(16KB数据页)从临时保险柜(Buffer Pool)搬到永久金库(表空间文件)。
-
他首先把整根金条的完整副本,小心翼翼地存放到 “安全中转站”(双写缓冲区)。这个中转站是磁盘上一块连续且特殊管理的区域(在MySQL 8.0.20之前位于系统表空间,之后是独立的
.dblwr
文件)。 -
关键点: 这个中转站的结构是精心设计的,确保写入整根16KB金条(页)是一个原子操作(要么全写进去,要么一点不写),避免了“拆小块”的风险。这步操作是顺序写(Sequential Write),相对较快。
-
-
第二步:再存永久金库(表空间文件)
-
确认金条安全完整地存到“中转站”后,管理员才开始执行原本的操作:把金条拆分成小块,搬运并存入永久金库对应的保险箱位置(真正的表空间数据文件位置)。这一步是随机写(Random Write),比较慢。
-
-
灾难发生时的“救命稻草”(崩溃恢复)
-
如果在第二步(存入永久金库)的过程中发生意外(如断电),导致金条在永久金库中损坏(部分写失效)。
-
银行重启后(数据库崩溃恢复),恢复专家(InnoDB Recovery)会做检查:
-
它发现永久金库里的某根金条残缺不全(校验和不匹配或页损坏)。
-
它立刻去 “安全中转站” 查找。哇!找到了这根金条完好无损的备份副本!
-
恢复专家用中转站里的完好副本,覆盖掉永久金库里那个损坏的金条。
-
金条被完美修复,账目恢复一致!
-
-
双写缓冲区的核心价值:绝对保障数据页的物理完整性
-
解决“部分写失效”的终极方案: 这是它存在的最根本原因。它确保了在任何情况下(崩溃、断电、存储故障),写入磁盘的每一个数据页在物理层面都是完整的、未损坏的。没有它,数据库在崩溃后可能面临无法修复的数据页损坏风险。
-
崩溃恢复的坚实后盾: 它让重做日志(Redo Log)如虎添翼。Redo Log 记录的是操作(“给张三账户加100元”),它能重放操作,但无法修复一个在物理上已经损坏的数据页本身。双写缓冲区则提供了损坏页的完好物理副本,是崩溃恢复时修复物理损坏的关键保障。
-
维护ACID中的D(持久性): 它确保了即使发生最恶劣的写入中断,最终写入磁盘的数据页也是正确的,是保障数据持久性(Durability)的重要底层机制。
付出的代价与优化
-
性能开销: 显而易见的代价是每次写数据页都需要多写一次磁盘(先写双写缓冲区,再写真实位置)。这带来了额外的I/O开销(主要是顺序写),对写入性能有一定影响。
-
为何值得付出?
-
数据安全无价: 相比数据损坏带来的灾难性后果(数据库无法启动、业务中断、数据丢失),这点性能开销是值得付出的保险成本。
-
顺序写优化: 写入双写缓冲区是顺序I/O(连续写入),比直接写入表空间文件的随机I/O(寻找分散位置)快很多。所以实际开销比想象的小。
-
-
何时考虑禁用(谨慎!):
-
只有在极其追求写性能,且能容忍极高数据损坏风险的非关键测试环境中,才可能通过设置
innodb_doublewrite=OFF
来禁用双写缓冲区。生产环境强烈不建议禁用!
-
3.2. 双写缓冲区中的数据保存在哪里?
在MySQL 8.0.20281, doublewrite 缓冲区位于InnoDB系统表室间中。从MySQL 8.0.20开
始, doublewrite 缓冲区默认存储区域位于数据目录下的 doubLewrite 文件中。
3.3.如何配置双写缓冲区?
是否启用 doublewrite 缓冲区可以通过系统变量 innode_doublewrite[=ON|OFF] 控制,默认为启用,如果真实的业务场景更关注性能而不是数据完整性,可以考虑禁用doublewrite缓冲区,例如在执行测试的环境中;只不过我们更多场景是启用双写缓冲区的
doublewrite文件所在目录通过系统变量 innode_doublewrite_dir (MySQL 8.0.20中引入)指定,如果不指定则在 innode_data_home_dir 目录(默认为data目录)下创建;如果指定doublewrite目录,建议设置在最快的存储介质上,以提高效率;
命名方式为: #ib_页大小_编号.dblwr,以上 #ib_16384_0.dblwr 的文件表示当前数据页的大小为16KB,编号为0; #ib_16384_1.dblwr 的文件表示当前数据页的大小为16KB,编号为1
双写文件的数量通过系统变量innode_doublewrite_files设置,默认情况下,为每个缓冲池实例创建两个doublewrite文件,也就是说文件数量为innode_buffer_pool_instances *2;此变量用于高级性能调优,大多数场景使用默认设置即可;