MySQL的日志系统

会有一股神秘感。 提交于 2020-01-17 15:26:34

前言

日志系统是用于保证MySQL数据不丢失、高性能和事务支持所需要的,不同的日志类型用于支持不同功能。下面列举MySQL目前使用的三种日志类型:

  • Bin Log
  • Undo Log
  • Redo Log

Bin Log

全称为二进制日志文件(Binary Log),是MySQL在Server层实现的一种日志。其作用是记录DML和DDL这类对数据有更改性质的操作,可以用来复制和恢复数据。bin log支持三种记录方式:

  • ROW:记录的是修改的数据的具体行
  • STATEMENT:以SQL语句形式记录
  • MIXED:混合模式。优先选择STATEMENT,STATEMENT无法记录的会由ROW来记录

MySQL提供了mysqlbinlog这个工具来操作binlog文件:
mysqlbinlog --no-defaults --start-datetime='2020-01-01' --stop-datetime='2020-01-15' -v --base64-output='decode-rows' log_bin.000001 > log.txt

  • no-defaults:表示不使用默认值,查看默认值可以输入mysqlbinlog --help
  • start-datetime/stop-datetime:只查看特定时间范围内的bin log日志
  • -v(–verbose):显示详细信息
  • –base64-output:设置输出格式,这里使用decode-rows解码
  • log_bin.000001:要操作的binlog文件
  • log.txt:将结果追加到log.txt文件
    下面使用这条语句打印row格式的binlog日志,该binlog记录了delete from test.t limit 1相关信息:

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200116  7:48:18 server id 50  end_log_pos 123 CRC32 0xfb15e2bd 	Start: binlog v 4, server v 5.7.28-log created 200116  7:48:18 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at 123
#200116  7:48:18 server id 50  end_log_pos 154 CRC32 0xfba4dd6c 	Previous-GTIDs
# [empty]
# at 154
#200116  7:48:24 server id 50  end_log_pos 219 CRC32 0xd547ddcb 	Anonymous_GTID	last_committed=0	sequence_number=1	rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#200116  7:48:24 server id 50  end_log_pos 291 CRC32 0x7e06ddc3 	Query	thread_id=2	exec_time=0	error_code=0
SET TIMESTAMP=1579160904/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 291
#200116  7:48:24 server id 50  end_log_pos 338 CRC32 0xbdd8f7b6 	Table_map: `test`.`t` mapped to number 109
# at 338
#200116  7:48:24 server id 50  end_log_pos 380 CRC32 0xc6f4c168 	Delete_rows: table id 109 flags: STMT_END_F
### DELETE FROM `test`.`t`
### WHERE
###   @1=5330617
###   @2='c'
# at 380
#200116  7:48:24 server id 50  end_log_pos 411 CRC32 0xa610a3b7 	Xid = 10
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

可以看到以三个#开头的,就是被decode翻译过的SQL语句,不过还是跟我们使用的SQL不太一样,它这里面的@1,@2都有固定意思,具体可以参考这个链接

好,我们再来看看STATEMENT格式的日志:

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200116  7:59:17 server id 50  end_log_pos 123 CRC32 0x9988edaf 	Start: binlog v 4, server v 5.7.28-log created 200116  7:59:17 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at 123
#200116  7:59:17 server id 50  end_log_pos 154 CRC32 0xfc792bbb 	Previous-GTIDs
# [empty]
# at 154
#200116  7:59:40 server id 50  end_log_pos 219 CRC32 0x276da709 	Anonymous_GTID	last_committed=0	sequence_number=1	rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#200116  7:59:40 server id 50  end_log_pos 298 CRC32 0xe0ecceec 	Query	thread_id=2	exec_time=0	error_code=0
SET TIMESTAMP=1579161580/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 298
#200116  7:59:40 server id 50  end_log_pos 393 CRC32 0xb9846488 	Query	thread_id=2	exec_time=0	error_code=0
use `test`/*!*/;
SET TIMESTAMP=1579161580/*!*/;
delete from t limit 1
/*!*/;
# at 393
#200116  7:59:40 server id 50  end_log_pos 424 CRC32 0x2773e433 	Xid = 10
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

找一下就能看到在较下方可以看到这条SQL语句。MIXED就是STATEMENTROW混合,这里就不列举了。

Undo Log

重做日志是MySQL在server层实现的一种日志,用于记录日志的更改前信息。目前普遍用于InnoDB的事务回滚,MVCC的支持。Undo Log记录在数据页格式为FIL_PAGE_UNDO_LOG,对应十六进制为0x02。Undo Log的数据页记录的具体记录也是一行一行的,每条记录都有一个7字节的隐藏字段DB_ROLL_PTR,用于指向Undo页具体的数据行,形成一个版本单向链表

以下例子只适用于InnoDB存储引擎,且隔离级别为READ-COMMITTED或REPEATABLE-READ

举个例子,假设现在有三条记录:

id name
1 张三
2 李四
3 王五

事务A:update t set name = “老李” where name = “李四”;
这里事务A执行了update语句后,还没提交或回滚时,就会生成一条新纪录"老李",并将这条纪录的DB_ROLL_PTR指向旧记录"李四"的地址。在其它事务试图读取这条数据的时候,就会顺着DB_ROLL_PTR来找到符合当前可见的记录,判断可见性是根据Read View和该数据的隐藏字段DB_TRX_ID来实现。关于Undo Log的原理不在这里介绍。

Redo Log

重做日志是InnoDB存储引擎实现高性能且避免数据丢失的一种日志。InnoDB为了提高性能,会尽可能的将操作只在内存中直接操作,而不马上刷到磁盘。为了避免宕机断电等情况导致内存的数据还没刷到磁盘上,导致数据丢失情况的发生。Redo Log会记录每次对数据操作的行为,并持久化到磁盘。关于Redo Log的原理不在这里介绍。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!