“InnoDB:InnoDB 磁盘结构”的版本间差异
无编辑摘要 |
|||
第11行: | 第11行: | ||
== InnoDB Data Dictionary(数据字典) == | == InnoDB Data Dictionary(数据字典) == | ||
InnoDB | InnoDB 数据字典由内部系统表组成,这些系统表包含用于跟踪对象(例如 表,索引和列)的元数据。 | ||
* 元数据实际上位于 InnoDB 系统表空间中。 | |||
* 由于历史原因,数据字典元数据在某种程度上与 InnoDB 表元数据文件(“.frm”文件)中存储的信息重叠。 | |||
# MySQL 8.0 之前: | |||
#: [[File:MySQL Data Dictionary before MySQL8.0.png|400px]] | |||
#: Data Dictionary 除了存在于 InnoDB 系统表空间,还存在于文件系统的“.FRM”,“.TRG”,“.OPT”⽂件中,还存在于系统表中(基于 MyISAM 存储引擎的⾮事务引擎表中)。【而且在一定程度上彼此的信息是重叠的】 | |||
# MySQL 8.0: | |||
#: [[File:Transactional Data Dictionary in MySQL8.0.png|400px]] | |||
#: Data Dictionary 全部存在于“Data Dictionary Storage Engine”(即 InnoDB 表中) | |||
=== 数据字典(InnoDB系统表) === | |||
InnoDB 中,实际上看不到系统表。有4个最基本的系统表来存储表的元数据:表、列、索引、索引列等信息。这4个表分别是“SYS_TABLES”、“SYS_COLUMNS”、“SYS_INDEXES”、“SYS_FIELDS”: | |||
# “'''SYS_TABLES'''”: | |||
#: 存储所有以 InnoDB 为存储引擎的表,每条记录对应一个表。该表的列分别是: | |||
#: <syntaxhighlight lang="mysql"> | |||
NAME:表名 | |||
ID:表的ID号 | |||
N_COLS:表的列数 | |||
TYPE:表的存储类型,包括记录的格式、压缩等信息 | |||
MIX_ID、MIX_LEN、CLUSTER_NAME:暂时未用 | |||
SPACE:这个表所在的表空间ID。 | |||
</syntaxhighlight> | |||
#: 这个表在 NAME 上有聚集索引,ID上有唯一二级索引。 | |||
# “'''SYS_COLUMNS'''”: | |||
#: 存储列信息,每一列对应一条记录。该表的列分别是: | |||
#: <syntaxhighlight lang="mysql"> | |||
TABLE_ID:该列所属表的ID | |||
POS:该列在表中第几列 | |||
NAME:列名 | |||
MTYPE:列的主数据类型 | |||
PRTYPE:列的精确数据类型 | |||
LEN:列数据长度,不包括 varchar 类型,因为该类型在记录里面已经存储了 | |||
PREC:列数据的精度。 | |||
</syntaxhighlight> | |||
#: 该表的主键列是(TABLE_ID,POS)。 | |||
# “'''SYS_INDEXES'''”: | |||
#: 存储索引信息,每条记录对应一个索引。该表的列分别是: | |||
#: <syntaxhighlight lang="mysql"> | |||
TABLE_ID:该列所属表的ID | |||
ID:索引的索引号 | |||
NAME:索引名 | |||
N_FIELDS:索引包含的列数 | |||
TYPE:索引类型,包括聚集索引、唯一索引、DICT_UNIVERSAL、DICT_IBUF | |||
SPACE:索引所在表的表空间ID | |||
PAGE_NO:该索引对应的 B+ 树的根页面号。 | |||
</syntaxhighlight> | |||
#: 该表主键(TABLE_ID,ID)。 | |||
# “'''SYS_FIELDS'''”: | |||
#: 存储定义的索引列,每条记录对应一个索引列。该表的列分别是: | |||
#: <syntaxhighlight lang="mysql"> | |||
INDEX_ID:该列所在的索引ID | |||
POS:该列在索引中第几列 | |||
COL_NAME:列名 | |||
</syntaxhighlight> | |||
#: 该表主键是(INDEX_ID,POS)。 | |||
== Doublewrite Buffer(双写缓冲区) == | == Doublewrite Buffer(双写缓冲区) == |
2021年4月19日 (一) 00:15的版本
Tables
Indexes
Tablespaces
InnoDB Data Dictionary(数据字典)
InnoDB 数据字典由内部系统表组成,这些系统表包含用于跟踪对象(例如 表,索引和列)的元数据。
- 元数据实际上位于 InnoDB 系统表空间中。
- 由于历史原因,数据字典元数据在某种程度上与 InnoDB 表元数据文件(“.frm”文件)中存储的信息重叠。
- MySQL 8.0 之前:
- MySQL 8.0:
数据字典(InnoDB系统表)
InnoDB 中,实际上看不到系统表。有4个最基本的系统表来存储表的元数据:表、列、索引、索引列等信息。这4个表分别是“SYS_TABLES”、“SYS_COLUMNS”、“SYS_INDEXES”、“SYS_FIELDS”:
- “SYS_TABLES”:
- 存储所有以 InnoDB 为存储引擎的表,每条记录对应一个表。该表的列分别是:
NAME:表名 ID:表的ID号 N_COLS:表的列数 TYPE:表的存储类型,包括记录的格式、压缩等信息 MIX_ID、MIX_LEN、CLUSTER_NAME:暂时未用 SPACE:这个表所在的表空间ID。
- 这个表在 NAME 上有聚集索引,ID上有唯一二级索引。
- “SYS_COLUMNS”:
- 存储列信息,每一列对应一条记录。该表的列分别是:
TABLE_ID:该列所属表的ID POS:该列在表中第几列 NAME:列名 MTYPE:列的主数据类型 PRTYPE:列的精确数据类型 LEN:列数据长度,不包括 varchar 类型,因为该类型在记录里面已经存储了 PREC:列数据的精度。
- 该表的主键列是(TABLE_ID,POS)。
- “SYS_INDEXES”:
- 存储索引信息,每条记录对应一个索引。该表的列分别是:
TABLE_ID:该列所属表的ID ID:索引的索引号 NAME:索引名 N_FIELDS:索引包含的列数 TYPE:索引类型,包括聚集索引、唯一索引、DICT_UNIVERSAL、DICT_IBUF SPACE:索引所在表的表空间ID PAGE_NO:该索引对应的 B+ 树的根页面号。
- 该表主键(TABLE_ID,ID)。
- “SYS_FIELDS”:
- 存储定义的索引列,每条记录对应一个索引列。该表的列分别是:
INDEX_ID:该列所在的索引ID POS:该列在索引中第几列 COL_NAME:列名
- 该表主键是(INDEX_ID,POS)。
Doublewrite Buffer(双写缓冲区)
doublewrite 缓冲区是一个存储区域,其中 InnoDB 在将页面写入 InnoDB 数据文件中的适当位置之前,先写入从缓冲池刷新的页面。如果在页面写入过程中发生 os,存储子系统或 mysqld 进程崩溃,则 InnoDB 可以在崩溃恢复期间从 doublewrite 缓冲区中找到该页面的良好副本。
尽管数据被写入两次,但双写缓冲区不需要两倍的 I/O 开销或两倍的 I/O 操作。只需对 os 进行一次“fsync()”调用,就可以将数据按较大的 Sequences 块写入 Doublewrite 缓冲区(除非将“innodb_flush_method”设置为“O_DIRECT_NO_FSYNC”)。
在大多数情况下,默认情况下会启用双写缓冲区。要禁用双写缓冲区,请将“innodb_doublewrite”设置为 0。
如果系统表空间文件(“ibdata文件”)位于支持原子写的 Fusion-io 设备上,则会自动禁用双写缓冲,并且将 Fusion-io 原子写用于所有数据文件。由于 doublewrite 缓冲区设置是全局的,因此,对于非 Fusion-io 硬件上驻留的数据文件,也禁用 doublewrite 缓冲。此功能仅在 Fusion-io 硬件上受支持,并且仅在 Linux 上的 Fusion-io NVMFS 中启用。要充分利用此功能,建议将“innodb_flush_method”设置为“O_DIRECT”。【???】
Redo Log(重做日志)【???】
重做日志是基于磁盘的数据结构,在崩溃恢复期间用于纠正不完整事务写入的数据。在正常操作期间,重做日志对更改表数据的请求进行编码,这些请求是由 SQL 语句或低级 API 调用引起的。在初始化期间以及接受连接之前,会自动重播未完成意外关闭之前未完成更新数据文件的修改。
默认情况下,重做日志在磁盘上由名为“ib_logfile0”和“ib_logfile1”的两个文件物理表示。 MySQL 以循环方式写入重做日志文件。重做日志中的数据根据受影响的记录进行编码;此数据统称为重做。数据通过重做日志的传递由不断增加的LSN值表示。
更改 InnoDB 重做日志文件的数量或大小
要更改 InnoDB redo log 文件的数量或大小,请执行以下步骤:
- 停止 MySQL 服务器,并确保它关闭且没有错误。
- 编辑“my.cnf”以更改日志文件配置。要更改日志文件的大小,请配置“innodb_log_file_size”。要增加日志文件的数量,请配置“innodb_log_files_in_group”。
- 再次启动 MySQL 服务器。
如果 InnoDB 检测到“innodb_log_file_size”与重做日志文件大小不同,则会写入日志检查点,关闭并删除旧的日志文件,以请求的大小创建新的日志文件,然后打开新的日志文件。
组提交以重做日志刷新
InnoDB 像其他任何符合 ACID 的数据库引擎一样,在提交事务之前先刷新该事务的 redo log。 InnoDB 使用 group commit 功能将多个此类刷新请求分组在一起,以避免每次提交都进行一次刷新。使用组提交,InnoDB 向日志文件发出一次写入操作,以对大约同时提交的多个用户事务执行提交操作,从而显着提高了吞吐量。
Undo Logs(撤消日志)【???】
撤消日志是与单个读写事务关联的撤消日志记录的集合。撤消日志记录包含有关如何撤消事务对聚集索引记录的最新更改的信息。如果另一个事务需要将原始数据视为一致读取操作的一部分,则将从撤消日志 Logging 检索未修改的数据。撤消日志存在于撤消日志段中,包含在rollback segments中。回滚段位于 system tablespace,undo tablespaces 和 temporary tablespace 中。
- 驻留在临时表空间中的撤消日志用于修改用户定义的临时表中的数据的事务。这些撤消日志未重做记录,因为崩溃恢复不需要它们。它们仅在服务器运行时用于回滚。这种类型的撤消日志通过避免重做日志 I/O 来提高性能。
InnoDB 支持最多 128 个回滚段,其中 32 个回滚段分配给了临时表空间。剩下的 96 个回滚段可以分配给修改常规表中数据的事务。
- “innodb_rollback_segments”变量定义 InnoDB 使用的回滚段数。
回滚段支持的事务数取决于回滚段中的撤消插槽数和每个事务所需的撤消日志数。
回退段中撤消插槽的数量根据InnoDB页的大小而有所不同。
InnoDB 页面大小 | 回滚段中的撤消插槽数(InnoDB 页面大小/ 16) |
---|---|
4096 (4KB) | 256 |
8192 (8KB) | 512 |
16384 (16KB) | 1024 |
32768 (32KB) | 2048 |
65536 (64KB) | 4096 |
一个事务最多可以分配四个撤消日志,以下每种操作类型都可以分配一个:
- “INSERT”对用户定义表的操作
- 用户定义的表上的“UPDATE”和“DELETE”操作
- “INSERT”对用户定义的临时表的操作
- 用户定义的临时表上的“UPDATE”和“DELETE”操作
撤消日志根据需要分配。例如,对常规表和临时表执行“INSERT”,“UPDATE”和“DELETE”操作的事务需要完全分配四个撤消日志。仅对常规表执行“INSERT”操作的事务需要单个撤消日志。
从已分配的系统表空间或撤消表空间回滚段中分配了对常规表执行操作的事务的撤消日志。从指定的临时表空间回滚段中分配了对临时表执行操作的事务的撤消日志。
分配给事务的撤消日志在其持续时间内一直与事务相关。例如,为常规表上的“INSERT”操作分配给事务的撤消日志将用于该事务对常规表上的所有“INSERT”操作。
给定上述因素,以下公式可用于估计 InnoDB 能够支持的并发读写事务数:
- 事务在达到 InnoDB 能够支持的并发读写事务数之前可能会遇到并发事务限制错误。当分配给事务的回滚段用尽撤消插槽时,就会发生这种情况。在这种情况下,请尝试重新运行事务。
- 当事务对临时表执行操作时,InnoDB能够支持的并发读写事务数受分配给临时表空间的回滚段数(即 32)所限制。
- 如果每个事务执行“INSERT”或“UPDATE”或“DELETE”操作,则 InnoDB 能够支持的并发读写事务数为:
(innodb_page_size / 16) * (innodb_rollback_segments - 32)
- 如果每个事务执行“INSERT”和“UPDATE”或“DELETE”操作,则 InnoDB 能够支持的并发读写事务数为:
(innodb_page_size / 16 / 2) * (innodb_rollback_segments - 32)
- 如果每个事务在临时表上执行“INSERT”操作,则 InnoDB 能够支持的并发读写事务数为:
(innodb_page_size / 16) * 32
- 如果每个事务在临时表上执行“INSERT”和“UPDATE”或“DELETE”操作,则 InnoDB 能够支持的并发读写事务数为:
(innodb_page_size / 16 / 2) * 32