MySQL数据库系统中的日志是数据库运行过程中非常重要的组成部分,它们记录了数据库的各种操作和状态信息,主要用于数据恢复、备份、性能调优、故障排查和主从复制。
错误日志
错误日志的作用
错误日志文件对于诊断和解决问题非常重要,它记录了以下类型的信息:
- MySQL服务器的启动和关闭过程。
- 服务器在启动和运行过程中遇到的错误。
- 事件调度器(Event Scheduler)的事件执行错误。
- 当服务器无法启动时,错误日志可能是唯一可以查看错误信息的地方。
错误日志的位置
错误日志文件的默认位置通常在MySQL的数据目录下,文件名通常是hostname.err
,其中hostname
是运行MySQL服务器的机器的主机名。
可以通过以下命令找到错误日志文件的位置:
SHOW VARIABLES LIKE 'log_error';
错误日志的配置
错误日志的配置可以通过以下几种方式进行:
- 配置文件:在MySQL的配置文件(通常是
my.cnf
或my.ini
,取决于操作系统)中设置log-error
选项来指定错误日志的文件路径。ini[mysqld] log-error=/path/to/your/mysqld.log
- 命令行:启动MySQL服务器时,可以通过命令行参数
--log-error[=file_name]
来指定错误日志文件。 - 运行时配置:在MySQL运行时,可以通过设置全局系统变量
log_error
来更改错误日志的位置。sqlSET GLOBAL log_error = '/path/to/your/mysqld.log';
错误日志的内容
错误日志文件包含以下类型的信息:
- 服务器启动和关闭的时间。
- 服务器启动时的配置信息。
- 服务器遇到的错误信息,包括错误代码和错误描述。
- 服务器启动失败的原因。
- 操作系统错误,例如文件权限问题或磁盘空间不足。
- 某些类型的管理命令,例如创建或删除数据库。
慢查询日志
慢查询日志(Slow Query Log)是MySQL数据库中用于记录执行时间超过指定阈值的查询语句的日志。它对于数据库性能调优非常有用,可以帮助开发者发现并优化那些消耗资源较多的查询。
慢查询日志的作用
慢查询日志的主要作用包括:
- 识别执行时间长的查询,以便进行优化。
- 分析数据库性能瓶颈。
- 监控数据库使用情况,特别是对于生产环境。
慢查询日志的配置
要启用慢查询日志,需要在MySQL的配置文件(通常是my.cnf
或my.ini
)中进行设置,或者通过MySQL命令行进行动态配置。以下是一些常用的配置选项:
slow_query_log
:设置为ON
以启用慢查询日志,设置为OFF
以禁用。slow_query_log_file
:指定慢查询日志文件的路径。long_query_time
:设置查询时间阈值(以秒为单位),超过这个时间的查询将被记录到慢查询日志中。默认值为10秒。log_queries_not_using_indexes
:如果设置为ON
,则即使查询不使用索引,也会被记录到慢查询日志中。
以下是一个配置示例:
[mysqld]
slow_query_log = ON
slow_query_log_file = /path/to/your/slow-query.log
long_query_time = 2
log_queries_not_using_indexes = ON
慢查询日志的内容
慢查询日志通常包含以下信息:
- 执行查询的时间。
- 查询的执行时间。
- 服务器解析查询的时间。
- 查询的用户和主机。
- 查询本身。
- 查询的锁定时间。
- 结果行的数量。
- 扫描的行数。
分析慢查询日志
分析慢查询日志通常涉及以下步骤:
- 定期检查慢查询日志文件,以发现潜在的慢查询。
- 使用文本编辑器或专门的工具(如
mysqldumpslow
、pt-query-digest
等)来分析日志。 - 对慢查询进行优化,可能包括添加索引、优化查询语句、调整数据库配置等。
通用查询日志
通用查询日志(General Query Log)是MySQL数据库中记录所有接收到的查询请求的日志。它提供了对数据库操作的详细记录,对于调试、审计和监控数据库的运行状况非常有用。
通用查询日志的作用
通用查询日志的主要作用包括:
- 跟踪和记录所有到达MySQL服务器的请求。
- 用于调试客户端应用程序与数据库的交互。
- 审计用户操作,例如可以用来查看特定用户执行了哪些查询。
- 监控数据库的使用情况,包括查询频率和类型。
通用查询日志的配置
要启用通用查询日志,需要在MySQL的配置文件(通常是my.cnf
或my.ini
)中进行设置,或者通过MySQL命令行进行动态配置。以下是一些常用的配置选项:
general_log
:设置为ON
以启用通用查询日志,设置为OFF
以禁用。general_log_file
:指定通用查询日志文件的路径。
以下是一个配置示例:
[mysqld]
general_log = ON
general_log_file = /path/to/your/general-query.log
通用查询日志的内容
通用查询日志通常包含以下信息:
- 请求的时间戳。
- 发起请求的用户和主机。
- 请求的类型(例如,连接、查询、断开连接等)。
- 执行的SQL语句。
以下是一个通用查询日志的示例条目:
2023-04-01T12:34:56.789Z 5 Query SELECT * FROM users WHERE id = 1
管理通用查询日志
查看状态:可以通过以下命令查看通用查询日志的状态:
sqlSHOW VARIABLES LIKE 'general_log%';
动态开启/关闭:可以在MySQL运行时动态开启或关闭通用查询日志:
sqlSET GLOBAL general_log = 'ON'; SET GLOBAL general_log = 'OFF';
轮换日志:可以通过重命名日志文件来轮换通用查询日志,然后重新启动MySQL服务器或刷新日志,或者使用以下SQL命令来刷新日志:
sqlFLUSH LOGS;
二进制日志
二进制日志(Binary Log)是MySQL数据库中一个非常重要的日志类型,它记录了所有对数据库数据的修改操作,不包括查询语句。这些修改操作包括数据定义语言(DDL)、数据操纵语言(DML)和数据控制语言(DCL)语句。
二进制日志的作用
二进制日志的主要作用包括:
- 数据恢复:在数据库发生故障时,可以使用二进制日志来恢复数据。
- 主从复制:在主从复制环境中,主服务器上的二进制日志被用于将数据更改复制到从服务器。
- 时间点恢复:可以恢复到特定的操作之前的状态。
- 数据库备份:通过备份Binlog,可以实现增量备份,只备份上次完整备份以来发生的变更,从而减少备份时间和存储成本。
二进制日志的配置
要启用二进制日志,需要在MySQL的配置文件(通常是my.cnf
或my.ini
)中进行设置。以下是一些常用的配置选项:
log-bin
:指定二进制日志的基本文件名。如果没有指定路径,默认位置在MySQL的数据目录下。server-id
:为服务器设置唯一的ID,这是主从复制中必需的。max_binlog_size
:设置单个二进制日志文件的最大大小,超过这个大小后,会自动创建新的日志文件。expire_logs_days
: 设置二进制日志文件的过期天数,超过这个时间的旧日志文件会被自动删除。binlog_format
:设置二进制日志的格式,可以是STATEMENT
、ROW
或MIXED
。
以下是一个配置示例:
[mysqld]
log-bin=/path/to/your/binlog
server-id=1
max_binlog_size=100M
binlog_format=ROW
二进制日志的内容
二进制日志的组成
二进制日志包含了一系列的“事件”(Event),每个事件代表一个数据库操作,如插入、更新、删除等。每个事件包含了相关操作的详细信息,如表名、列名、修改前后的值等。
常见事件类型:
- Query事件:记录对数据库执行的SQL语句。
- TableMap事件:将表的ID映射到表名,指示接下来的事件涉及哪个表。
- WriteRows、UpdateRows、DeleteRows事件:分别记录对表的写入、更新和删除操作。
- Xid事件:表示一个事务的提交。
- Rotate事件:表示切换到下一个Binlog文件。
二进制日志的类型
二进制日志的类型主要分为Statement模式、Row模式和Mixed模式。
Statement-Based Replication (SBR, 基于语句的复制)
在Statement模式下,二进制日志记录的是每条修改数据的SQL语句,而不是数据本身。这意味着日志中会记录像INSERT、UPDATE、DELETE这样的SQL语句文本。
- 优点:
- 简单直观:因为复制的是 SQL 语句本身,所以很容易理解和跟踪发生了什么变化。
- 存储空间节省:相比 Row 模式,Statement 模式下的日志通常占用更少的空间,因为只记录了 SQL 语句而不是具体的数据行。
- 缺点:
- 非确定性问题:有些 SQL 语句的结果依赖于执行上下文(如触发器、用户变量、随机函数等),这可能导致主服务器和从服务器之间的结果不一致。
- 不适用于所有情况:当涉及到复杂的功能(如存储过程、触发器、视图等)时,Statement 模式可能无法完全保证数据一致性。
Row-Based Replication (RBR, 基于行的复制)
在 Row 模式下,MySQL 记录每一条被修改的数据行。这意味着每个数据行的变化都会被记录下来,无论这些变化是由哪些 SQL 语句引起的。
优点:
- 高度确定性:由于记录的是具体的行变化,因此避免了 Statement 模式中可能遇到的非确定性问题。
- 广泛适用:适用于所有 SQL 语句和功能,包括那些在 Statement 模式下可能引起问题的情况。
缺点:
- 存储空间占用较多:相比于 Statement 模式,Row 模式的日志文件通常要大得多,因为它们记录了每一行的具体变化。
- 性能开销:记录每一行的变化可能会导致较高的 CPU 和 I/O 开销。
Mixed-Based Replication (MBR, 混合模式复制)
Mixed模式是Statement模式和Row模式的混合体。MySQL服务器会根据执行的SQL语句来决定使用哪种模式。对于大多数操作,它使用Statement模式,但当Statement模式可能导致非确定性结果时,它会自动切换到Row模式。
- 优点:
- 高效且安全:结合了 Statement 模式节省空间的优点和 Row 模式避免非确定性问题的能力。
- 灵活性:自动检测并处理可能导致问题的 SQL 语句,从而避免数据不一致的问题。
- 工作原理:
- 默认行为:在 Mixed 模式下,默认采用 Statement 模式来记录数据更改。
- 自动切换:当 MySQL 检测到某个 SQL 语句可能引起非确定性问题时(例如涉及用户变量、触发器、临时表等),它会自动切换到 Row 模式来记录这些更改。
在 MySQL 配置文件(如 my.cnf
或 my.ini
)中设置 binlog_format=mixed
可以启用 Mixed 模式。
查看Binlog内容
二进制日志是二进制格式的,不能直接用文本编辑器查看。要查看二进制日志的内容,可以使用mysqlbinlog
工具。 以下是一个使用mysqlbinlog
查看二进制日志的示例:
mysqlbinlog /path/to/your/binlog.000001
binlog刷盘过程
MySQL在写入binlog时,首先会将日志事件写入到一个内存缓冲区(binlog cache)中。
每个线程都有自己的binlog cache,这些缓存是独立的,不会相互影响。
如果binlog cache满了,即使事务没有提交,MySQL也会将binlog cache中的内容写入磁盘,以释放缓存空间。
如果会话结束,MySQL也会将binlog cache中的内容写入磁盘。
即使没有上述情况,MySQL也会定期将binlog cache中的内容写入磁盘,这个周期由sync_binlog
系统变量控制。
sync_binlog
参数控制MySQL如何将binlog cache中的数据同步到磁盘。
- 当
sync_binlog
设置为0时,MySQL不会主动同步binlog到磁盘,而是依赖于操作系统的文件系统缓存。这可能会在系统崩溃时丢失数据。 - 当
sync_binlog
设置为1时,每次事务提交都会执行一次fsync()
操作,确保binlog数据写入磁盘。 - 如果设置为N(N>1),则每N次事务提交后执行一次
fsync()
操作。
当满足上述任一刷盘条件时,MySQL会将binlog cache中的数据通过文件系统写入到binlog文件中。
如果sync_binlog
设置为1,写入操作会伴随一个fsync()
调用,确保数据真正落盘。
如果是N值,则每N次写入后调用一次fsync()
。
管理二进制日志
- 查看二进制日志:使用
mysqlbinlog
工具或SQL命令SHOW BINLOG EVENTS
。 - 删除二进制日志:使用
PURGE BINARY LOGS
或RESET MASTER
(删除所有二进制日志)。 - 设置二进制日志过期时间:通过
expire_logs_days
选项设置日志自动删除的天数。 - 轮换二进制日志:执行
FLUSH LOGS
命令或在达到max_binlog_size
限制时自动轮换。
expire_logs_days
选项:在指定的天数之后,系统会自动清理旧的二进制日志文件,释放存储空间。如果设置为0,则不会自动删除任何二进制日志文件,除非手动执行删除操作。
max_binlog_size
选项:当当前日志文件达到这个大小时,MySQL会自动轮换日志,即关闭当前日志文件并创建一个新的日志文件。
中继日志
中继日志(Relay Log)是MySQL复制环境中使用的一种日志,主要在从服务器(也称为从节点或副本)上使用。中继日志用于存储从主服务器接收到的二进制日志(Binary Log)事件,这些事件随后在从服务器上重放,以保持主从数据的一致性。
中继日志的作用
中继日志的主要作用是:
- 数据复制:从服务器从中继日志中读取事件,并在本地数据库上执行这些事件,从而实现数据的复制。
- 缓冲区:中继日志作为从服务器上的一种缓冲机制,允许从服务器在主服务器上发生更改时不必立即应用这些更改。
中继日志的配置
中继日志通常不需要手动配置,当设置从服务器时,它会自动启用。但是,可以设置一些与中继日志相关的选项:
relay_log
:指定中继日志文件的路径和基本文件名。relay_log_index
:指定中继日志索引文件的路径,该文件包含当前使用的中继日志文件的列表。relay_log_info_repository
:指定存储中继日志位置信息的方式,可以是FILE
或TABLE
。
以下是一个配置示例:
[mysqld]
relay_log=/path/to/your/relay-bin
relay_log_index=/path/to/your/relay-bin.index
relay_log_info_repository=TABLE
中继日志的内容
中继日志的内容与主服务器上的二进制日志非常相似,它包含了一系列的事件,这些事件代表了主服务器上发生的数据更改。
中继日志文件默认保存在从服务器的数据目录下,文件名的格式通常是“从服务器名 - relay-bin.序号”,还有一个索引文件“从服务器名 - relay-bin.index”,用于定位当前正在使用的中继日志。
中继日志是二进制格式的,不能直接用文本编辑器查看。要查看中继日志的内容,可以使用mysqlbinlog
工具。
管理中继日志
- 查看中继日志:使用
mysqlbinlog
工具或SQL命令SHOW RELAYLOG EVENTS
。 - 删除中继日志:中继日志通常会在不需要时自动删除,但也可以手动删除。使用
PURGE RELAY LOGS
命令可以删除所有未为中继日志设置过期时间的中继日志。 - 设置中继日志过期时间:通过
relay_log_purge
选项设置为ON
来自动删除不再需要的中继日志,relay_log_expire_logs_seconds
选项可以设置中继日志的过期时间。
事务日志
事务日志是对InnoDB 存储引擎中的 Redo 日志和 Undo 日志的统称。
事务日志对于保证事务的原子性、一致性、隔离性和持久性(ACID属性)起着至关重要的作用。
事务日志的作用
事务日志的主要作用包括:
- 确保事务的持久性:事务日志记录了所有对数据库的修改操作,即使发生系统故障,也能保证这些操作不会丢失。
- 崩溃恢复:在系统崩溃后重启时,InnoDB使用事务日志来恢复未提交的事务。
- 减少磁盘I/O:通过将事务的修改先写入日志文件,而不是直接写入数据文件,可以减少磁盘I/O操作,提高性能。
事务日志的配置
事务日志的配置涉及几个关键参数,通常在MySQL的配置文件(my.cnf
或my.ini
)中进行设置:
innodb_log_file_size
:设置每个事务日志文件的大小。innodb_log_files_in_group
:设置事务日志文件组的数量,通常为2个。innodb_log_group_home_dir
:设置事务日志文件组的存储路径。innodb_undo_directory
: 设置 Undo 日志文件所在的目录。innodb_undo_logs
: 设置 Undo 日志文件的数量。
以下是一个配置示例:
[mysqld]
innodb_log_file_size = 256M
innodb_log_files_in_group = 2
innodb_log_group_home_dir = /path/to/your/innodb_logs
事务日志的内容
事务日志包含以下类型的信息:
- 重做记录(Redo Records):记录了事务对数据页所做的修改。
- 撤销记录(Undo Records):记录了用于回滚事务的信息。
- 日志序列号(LSN):一个唯一的序列号,用于标识事务日志中的位置。
InnoDB Redo 日志
Redo 日志是一种写前日志(Write-Ahead Logging, WAL),它记录了对数据页的物理更改。
当一个事务开始时,InnoDB 将事务涉及的数据页更改记录到 Redo 日志中。
如果数据库崩溃,InnoDB 可以通过 Redo 日志恢复未提交事务的更改,从而保证数据的一致性。
Redo 日志的特点
- 持久性:Redo 日志是持久的,即使在系统崩溃后也能用于恢复。
- 顺序写入:Redo 日志是顺序写入磁盘的,这使得写入效率较高。
- 循环使用:Redo 日志文件是循环使用的,当一组文件写满后,会回到第一个文件重新写入。
Redo 日志记录的内容
Redo Log记录的内容主要是针对数据库页的物理更改。具体来说,它记录了在事务执行过程中对数据库页所作的每一次修改。这些修改包括但不限于:
- 数据页的修改:记录了数据页上的每一个字节级别的改变,例如某个页的某个偏移量处的数据从
'xxx'
变成了'yyy'
。 - 事务提交标识:在事务提交时,会记录一个特殊的标志,表示该事务已经完成。
- 元数据更新:例如B+树节点的调整、索引的创建或删除等操作。
- 检查点信息:记录了检查点的位置,用于标识系统崩溃后应该从哪里开始重做日志记录。
Redo 日志的结构
Redo Log的结构可以从多个层面来理解,主要包括内存中的Redo Log Buffer和磁盘上的Redo Log Files。
Redo Log Buffer
- 内存中的缓冲区:Redo Log Buffer是InnoDB在内存中预留的一片连续内存空间,用于暂存即将写入磁盘的日志记录。这样做的好处是可以减少直接写入磁盘的次数,提高写入效率。
- 大小:Redo Log Buffer的大小固定为16MB,这有助于在系统崩溃时能够快速地从内存中恢复未写入磁盘的日志记录。
- 组织方式:Redo Log Buffer被划分为多个redo log block,每个block可以容纳一条或多条日志记录。
Redo Log Files
- 磁盘上的文件:Redo Log记录最终会被写入到磁盘上的Redo Log Files中。这些文件通常是循环使用的,即当文件写满后会从头开始覆盖旧的日志。
- 文件数量和大小:默认情况下,InnoDB会在数据目录中创建多个Redo Log文件,每个文件的大小和数量可以通过配置参数
innodb_log_file_size
和innodb_log_files_in_group
来设定。通常建议至少有两个文件,这样可以在一个文件正在被刷新到磁盘时,另一个文件继续接收新的日志记录。 - 循环写入:Redo Log Files按照循环的方式写入,当一个文件写满后,写入操作会切换到下一个文件,当所有文件都被写满后,写入操作又会回到第一个文件开始覆盖最早的记录。
Redo Log Record格式
- Header:每个Redo Log记录都有一个头部,包含记录的类型、长度等信息。
- Payload:这部分包含了具体的日志内容,描述了对数据库页所做的修改,包括页ID、偏移量、修改前后的数据等。
- Footer:记录的尾部通常包含校验信息,如CRC32校验码,用于验证日志记录的完整性。
Redo Log Segment
nnoDB将Redo Log分成多个段(Segment),每个段包含一定数量的记录。这种组织方式有助于管理和查找日志记录。
Checkpoint
InnoDB会记录一个称为“Checkpoint”的位置,指示了最后一个被持久化的日志记录的位置。这有助于在恢复过程中确定哪些日志记录需要被重做。
Redo 日志的写入流程
- 写入Redo Log Buffer:当事务对数据进行修改时,InnoDB会先将这些修改记录到内存中的Redo Log Buffer。
- 刷新到Redo Log File:Redo Log Buffer中的数据会定期或者在某些条件下(如事务提交)被刷新到磁盘上的Redo Log Files。
- 持久化:为了保证持久性,Redo Log记录在事务提交之前必须被写入到磁盘。这通常通过配置参数
innodb_flush_log_at_trx_commit
来控制。
Redo 日志的刷盘时机
Redo Log的刷盘时机可以通过系统参数innodb_flush_log_at_trx_commit来控制,它可以设置为0、1、2三个值,分别代表不同的刷盘策略。
- 事务提交时刷盘
- innodb_flush_log_at_trx_commit=1:每次事务提交都会将日志缓冲中的数据写入操作系统缓冲区,并立即调用
fsync()
方法将数据持久化到磁盘。这种模式可以确保数据的强持久性,但IO性能较差。 - innodb_flush_log_at_trx_commit=2:每次事务提交只是将日志写入操作系统缓冲区,然后后台线程每隔一秒通过
fsync()
方法将数据从操作系统缓冲区刷新到磁盘。这种方式在性能和持久性之间取得了平衡。 - innodb_flush_log_at_trx_commit=0:事务提交时不会立即将日志缓存写到文件(操作系统缓冲区),而是等待后台线程每秒刷新一次。这种模式性能较好,但可能丢失最多1秒的数据。
- innodb_flush_log_at_trx_commit=1:每次事务提交都会将日志缓冲中的数据写入操作系统缓冲区,并立即调用
- 后台线程定时刷盘
- 定时刷新:InnoDB存储引擎有一个后台线程,每隔1秒将日志缓冲中的数据写入操作系统缓冲区,并调用
fsync()
方法将其持久化到磁盘。这个过程独立于事务提交操作。
- 定时刷新:InnoDB存储引擎有一个后台线程,每隔1秒将日志缓冲中的数据写入操作系统缓冲区,并调用
- 非提交事务的刷盘
- 缓冲区占用超过阈值:当日志缓冲中的数据占用量即将达到其总容量的一半时,后台线程会主动将其写入磁盘。这种情况下,日志只通过
write
方法写入操作系统缓冲区,并不进行fsync()
操作。 - 并行提交事务时的刷盘:如果多个事务并行提交,某些事务的部分日志会顺带持久化到磁盘。例如,假设有两个事务A和B,它们的日志存在于同一个日志缓冲区。当事务B提交时,会触发日志的持久化操作,此时事务A的一部分日志也会被顺带持久化到磁盘。
- 缓冲区占用超过阈值:当日志缓冲中的数据占用量即将达到其总容量的一半时,后台线程会主动将其写入磁盘。这种情况下,日志只通过
参考链接:
InnoDB Undo 日志
Undo 日志记录了事务在更改数据之前的数据状态,这样如果事务回滚,InnoDB 可以通过 Undo 日志恢复数据到更改前的状态。
Undo 日志的特点
- 事务回滚:Undo 日志使得事务可以回滚到开始状态。
- 多版本并发控制 (MVCC):Undo 日志还用于实现多版本并发控制,这样多个事务可以同时读取相同的数据但看到不同的版本。
Undo 日志的结构
Undo Tablespaces:Undo Log可以存储在专用的Undo表空间中,这些表空间独立于系统表空间。从MySQL 5.6版本开始,默认情况下Undo Log存储在单独的Undo表空间文件中,这提高了系统的灵活性和性能。通过
innodb_undo_directory
和innodb_undo_tablespace
等参数可以指定Undo表空间文件的存放位置和数量。Rollback Segments:Undo Log是以Rollback Segment的形式组织的。每个Rollback Segment可以视为一个Undo Log的容器,它包含了一系列的Undo Slots。Rollback Segments用于组织和管理Undo Log记录,使得Undo Log的管理更加高效。
Undo Slots:每个Rollback Segment包含多个Undo Slots,每个Slot用于存储一个事务的Undo Log记录。当一个事务开始时,它会分配一个Undo Slot,并在其中记录Undo Log。
Undo Pages:Undo Log记录存储在InnoDB的数据页中。每个Undo Page可以存储一定数量的Undo Log记录。Undo Page是Undo Log的实际物理存储单位。
Undo Record的结构
Undo Record是Undo Log的基本组成单元,它保存了足够的信息来恢复一个数据行到一个先前的状态。具体来说,Undo Record包括以下几个部分:
- TRX_ID:事务ID,用于标识生成这条记录的事务。
- ROLL_PTR:回滚指针,用于链接Undo Log记录。这个指针帮助InnoDB追踪一系列的Undo Log记录,这对于事务回滚时恢复数据至关重要。
- Undo Number:表示Undo Log记录在Undo Segment中的顺序号。
- Undo Type:指示Undo Log记录的类型,例如:
TRX_UNDO_INSERT_REC
:表示INSERT操作的Undo Log。TRX_UNDO_UPDATE_BY_INDEX
:表示UPDATE操作的Undo Log。TRX_UNDO_DELETE_BY_INDEX
:表示DELETE操作的Undo Log。
- Before Image (BI):数据在被修改前的状态。对于UPDATE操作,Undo Log会保存数据行修改前的状态;对于DELETE操作,则会保存被删除数据行的所有字段值。
- Row ID:对于UPDATE和DELETE操作,记录了被修改或删除行的主键或行标识符。
- Other Flags and Metadata:其他标记位和元数据信息,比如是否已提交等。
Undo 日志的生命周期
当一个事务启动后,InnoDB会为该事务预留Undo Log的空间。然后,实际上写入Undo Log的行为取决于事务中具体的操作类型:
- UPDATE操作:当执行UPDATE操作时,InnoDB会在执行实际的数据修改之前,先记录下修改前的数据状态(即Before Image)到Undo Log中。这样做是为了如果事务需要回滚,可以利用Undo Log恢复到修改前的状态。
- DELETE操作:在执行DELETE操作时,InnoDB同样会在删除记录之前记录该记录的Before Image到Undo Log中,以便在回滚时可以重新插入这些记录。
- INSERT操作:对于INSERT操作,虽然没有Before Image,但InnoDB仍会生成Insert Undo Log。这是因为如果事务失败或被回滚,InnoDB需要能够移除那些由该事务插入的新记录。
在事务提交之前,所有修改的数据都会产生相应的Undo Log记录。这意味着,在事务提交或回滚时,InnoDB已经有了完整的Undo Log记录,可以用来恢复到事务开始前的状态。
Undo Log也是实现MVCC的关键。当数据行被修改时,旧版本的数据会被记录在Undo Log中,这样就可以允许并发的读取事务看到这些旧版本的数据。
事务提交后,InnoDB还会写入Redo Log,用于崩溃恢复。
当事务提交后,InnoDB不会立即删除Undo Log。它们会被标记为可回收,并保留在Undo表空间中,直到被后台的purge线程清理。
后台的purge线程会定期检查Undo Log,如果发现某些Undo Log不再需要,就会将其从Undo表空间中移除。
- 事务已经提交,且Undo Log不再需要用于回滚。
- 事务已经提交,且Undo Log不再需要用于MVCC。
- 事务已经提交,且Undo Log已经被复制到Redo Log。
可以通过调整一些系统参数来影响 Undo Log 的管理和清理行为,例如 innodb_purge_batch_size
控制每次 Purge 操作处理的行数,innodb_purge_threads
控制 Purge 操作使用的线程数量等。
参考链接:
两阶段提交
在MySQL使用InnoDB存储引擎时,两阶段提交用于确保二进制日志(binlog)和事务日志(redolog)之间的一致性,特别是在涉及更新操作的事务中。
第一阶段:准备阶段(Prepare Phase)
- 事务开始:客户端发起一个事务,这个事务可能包含多个对数据库的修改操作。
- 记录事务日志:InnoDB存储引擎为事务中的每个操作生成重做记录(redo log),并将这些记录写入到事务日志缓冲区(log buffer)。
- 写入事务日志:在事务提交前,InnoDB会将log buffer中的内容刷新到磁盘上的事务日志文件(redolog)中。
- 准备提交:当事务准备好提交时,InnoDB会先执行一个“准备”操作,此时事务的状态变为“准备好”。
第二阶段:提交阶段(Commit Phase)
- 写入二进制日志:在事务进入提交阶段之前,MySQL服务器会将事务的所有修改操作记录到二进制日志缓冲区(binlog cache)中,并在准备提交时将binlog cache中的内容写入到磁盘上的二进制日志文件(binlog)中。
- 提交事务:MySQL服务器向InnoDB存储引擎发送提交命令。
- 写入提交记录:InnoDB接收到提交命令后,会在事务日志中写入一个“提交”记录,并将这个记录也刷新到磁盘上的事务日志文件中。
- 完成提交:一旦事务日志中的“提交”记录被写入磁盘,InnoDB会认为事务已经提交,并将事务标记为“已提交”。
管理事务日志
- 检查事务日志状态:可以使用以下命令来查看事务日志的相关信息:sql
SHOW VARIABLES LIKE 'innodb_log%';
- 轮换事务日志:InnoDB会自动轮换事务日志,当当前日志文件写满时,会切换到下一个日志文件。
- 清理事务日志:事务日志通常不需要手动清理,InnoDB会定期清理不再需要的事务日志。
- 监控 InnoDB 状态:使用
SHOW ENGINE INNODB STATUS;
查看 InnoDB 的整体状态信息,包括 Redo 和 Undo 日志的状态。