🖥️ Server 层日志
错误日志
错误日志是 MySQL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。
当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。查看日志位置:
|
|
查询日志
查询日志中记录了客户端的所有操作语句。(binlog 不包含查询数据的 SQL 语句)
默认情况下,查询日志是未开启的。
如果需要开启查询日志,可以修改MySQL的配置文件 /etc/my.cnf 文件,添加如下内容:
|
|
开启了查询日志之后,/var/lib/mysql/ 目录下就会出现 mysql_query.log 文件。
所有的客户端的增删改查操作都会记录在该日志文件之中,长时间运行后,该日志文件将会非常大。
慢查询日志
慢查询日志记录了:
- 执行时间超过
long_query_time
- 扫描记录数大于
min_examined_row_limit
的所有的SQL语句的日志,默认未开启。
如果需要开启慢查询日志,需要在 MySQL 的配置文件 /etc/my.cnf 中配置如下参数:
|
|
默认情况下,不会记录管理语句,也不会记录不使用索引进行查找的查询。
|
|
🔢 bin log
二进制日志(bin log)是记录了所有的数据库表结构变更(DDL)和表数据修改(DML)的日志。
作用:
- 数据归档
- 灾难时数据恢复
- MySQL 主从复制
|
|
log_bin_basename
- 当前数据库服务器的binlog日志的基础名称(前缀),具体的binlog文件名需要再该basename的基础上加上编号(编号从000001开始)。
log_bin_index
- binlog的索引文件,里面记录了当前服务器关联的binlog文件有哪些。
binlog 格式
MySQL 服务器中提供了多种格式来记录二进制日志:
配置二进制日志的格式,只需要在 /etc/my.cnf 中配置 binlog_format 参数即可。
📃
statement
- 基于 SQL 语句的日志记录,记录的是 SQL 语句,对数据进行修改的 SQL 都会记录在日志文件中。
📕
row
(默认)- 基于行的日志记录,记录的是每一行的数据变更。
🖇️
mixed
- 混合了 statememt 和 row 两种格式,默认采用statement,在某些特殊情况下会自动切换为 row 进行记录。
|
|
查看 bin log
日志是以二进制方式存储的,不能直接读取,需要通过二进制日志查询工具 mysqlbinlog
来查看。
|
|
清理 bin log
reset master
- 删除全部 binlog 日志,删除之后,日志编号,将从 binlog.000001重新开始
purge master logs to 'binlog.000005'
- 删除 000005 之前的所有日志
purge master logs before 'yyyy-mm-dd hh24:mi:ss'
- 删除日志为 “yyyy-mm-dd hh24:mi:ss” 之前产生的所有日志
可以在 mysql 的配置文件中配置二进制日志的过期时间,设置了之后,二进制日志过期会自动删除。
|
|
💽 InooDB 存储引擎日志
⏱️ redo log 重做日志
MySQL 更新数据操作的都是 Buffer Pool 内存中的缓存页,被修改过的脏页不会立即被刷新到磁盘中(随机磁盘 IO 性能低),为了防止断电等情况造成内存中的数据丢失,利用 redo log 记录数据页的更新操作,后续在合适的时间再修改磁盘中的数据。(WAL 技术)
redo log 是物理日志,记录了数据页做了什么修改。例如:对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了 AAA 更新。
redo log 记录了事务完成后的数据状态,当事务提交时,只要将 redo log 持久化到硬盘即可(顺序磁盘 IO),不需要将 Buffer Pool 中的脏页持久化到硬盘(随机磁盘 IO)。
保证了事务 ACID 特性中的持久性,当数据库发生故障时,可以利用 redo log 恢复数据。
🔃 redo log 循环写
redo log 是为了防止 Buffer Pool 中的脏页丢失而设计的。当随着服务的运行,Buffer Pool 中的脏页刷新到了磁盘中,redo log 中的记录就没有用了,可以擦除旧记录。
所以 redo log 采用了循环写的方式,数据写到末尾又会回到文件的开头,新数据可以覆盖无用的旧数据。
刷盘
产生的 redo log 并不是直接写入磁盘的,会先写到 redo log buffer 中,后续再持久化到磁盘。
redo log buffer 默认大小为 innodb_log_Buffer_size = 16MB
,增加它的大小,可以让 MySQL 处理大事务不必写入到磁盘,进而提升 IO 性能。
redo log buffer 刷盘时机:
InnoDB 的后台线程,每隔 1s,会将 redo log buffer 持久化到磁盘
redo log buffer 中记录的写入量大于设置空间的一半时
MySQL 正常关闭时
每次事务提交时,将 redo log buffer 中 redo log 持久化到磁盘
innodb_flush_log_at_trx_commit
控制
两阶段提交
redo log 和 bin log 持久化到硬盘,是两个独立的操作,可能会出现半成功的状态,导致两份日志之间的逻辑不一致。
为了避免这个问题,保证两个日志的一致性,使用了”两阶段提交“来解决。把单个事务的提交拆分成了两个阶段:
Prepare 准备阶段
Commit 提交阶段
将 redo log 写入拆成了两个步骤:prepare 和 commit,中间再穿插写入 bin log。
redo log prepare -> bin log -> redo log commit
当 bin log 成功持久化到磁盘,就被认为事务已经执行成功(即使 redo log 是 prepare 也没有关系)。
🔙 undo log 回滚日志
undo log 是一种用于撤销回滚的日志。InnoDB 更新记录前,会将操作前的数据记录的 undo 中,当事务回滚时,利用 undo log 进行回滚。
undo log 主要用于:
🎗️ 实现事务回滚,保障事务 ACID 中的原子性
🎗️ undo log 与 ReadView 配合,实现 MVCC
在 InnoDB 存储引擎对记录进行修改时,会把回滚需要的信息全部记录到 undo 中,如果发生回滚,就会读取 undo log,然后执行与之相反的操作。
➕ 插入数据,记录这条数据的主键,回滚时根据主键把该条记录删除
➖ 删除数据,记录这条数据的所有内容,回滚时将这些内容组成的记录插入表中
🖋️ 更新数据,
- 更新了主键,会记录两条 undo log,一条删除的,一条更新的
- 没有更新主键,记录这条数据更新列的旧值,回滚时将数据更新为旧值
版本链
一条记录的每次更新操作产生的 undo log 格式都会有:
trx_id 事务 id
记录了该记录是由哪一个事务修改的。
roll_pointer 回滚指针
回滚指针可以将 undo log 串连成一个链表,这个链表称为版本链。