MySQL的binlog日志

Posted god-jiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL的binlog日志相关的知识,希望对你有一定的参考价值。

前言

相信很多用过mysql开发的程序员们都知道binlog,binlog可以用来归档,也可以用来做主备同步。毫无夸张地说,MySQL能够成为现今最流行的数据库,binlog功不可没,今天就来分享一下binlog里面的内容

binlog三种格式对比

相信大家都知道binlog有两种格式,一种是statement,一种是row,但是还会从别的资料看到第三种格式,叫mixed,mixed其实就是前面两种格式的混合

为了描述三种格式的区别,我先来创建一张表,并且初始化5条数据

create table t(
	id int(11) NOT NULL,
	a int(11) DEFAULT NULL,
	u_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY(id),
	KEY a(a),
	KEY u_time(u_time)
)ENGINE=InnoDB;

insert into t values(1,1,'2021-11-18');
insert into t values(2,2,'2021-11-17');
insert into t values(3,3,'2021-11-16');
insert into t values(4,4,'2021-11-15');
insert into t values(5,5,'2021-11-14');

如果在这张表中删除一行记录的话,我们来看看binlog是怎么记录的
sql语句如下:

delete from t where a>=4 and u_time<='2021-11-15' limit 1

接下来看看三种格式的binlog怎么记录的

1、binlog=statement格式

当binlog=statement时,binlog记录的是SQL本身的语句

ues `test`;delete from t where a>=4 and u_time<='2021-11-15' limit 1

binlog设置为statement格式的时候,因为记录的是sql语句本身,并且语句带limit 1,这个命令可能是unsafe的。这里我来说明一下为啥:

  1. 如果delete使用的是索引a,根据索引a找到第一条数据删除,也就是删除a=4这一行;
  2. 如果使用索引u_time,那么找到就是u_time='2021-11-14’这一条,也就是a=5这一行

由于statement格式下,binlog记录的是sql原文,可能导致在主库执行的时候使用的是索引a,而在备库执行的时候用了索引u_time,因此,会出现主备不一致的情况

那么怎么解决主备不一致呢?MySQL的另一种格式row

2、binlog=row格式

如果我们把binlog设置为row格式的时候,binlog记录的不是sql原语句,而是替换成了两个event:Table_map和Delete_rows。

Table_map    |   table_id: 226(test.t)
Delete_rows  |   table_id: 226 flags: STMT_END_F
  1. Table_map event,用于说明接下来要操作的表是test库的t表
  2. Delete_rows event,用于定义删除的行为

通过对row格式的binlog看不出详细信息,需要进一步借助mysqlbinlog工具,用’mysqlbinlog -w data/master.0.000001 -start -position=8900’解析和查看binlog的内容,binlog可以看到这条语句是从8900事物开始,所以可以用start-position指定从哪个位置开始解析

最后可以查看到binlog使用row格式,binlog里面记录了真实删除记录的主键id,这样备库同步的时候一定会删除id=4的行,不会有主备同步不一致的问题

3、binlog=mixed格式

上面已经有了row格式,已经可以解决主备不一致的问题,为啥还会有mixed格式呢

  • statement格式记录sql原句,可能会导致主备不一致,所以出现了row格式
  • 但是row格式也有一个缺点,就是很占空间,比如你delete语句删除1万行记录,statement格式会记录一个sql删除1万行就没了;但是使用row格式会把这1万要删除的记录都写到binlog中,这样会导致binlog占用了大量空间,同时写binlog也要耗费大量IO,影响mysql的整体速度
  • 所以MySQL出了个mixed格式,它是前面两种格式的混合。意思是MySQL自己会判断这条SQL语句是否会引起主备不一致,是的话就会使用row,否则就用statement格式
  • 也就是说上面delete语句加上了limit 1,MySQL认为会引起主备不一致,它就会使用row格式记录到binlog;如果delete 1万行记录,MySQL认为不会引起主备不一致,它就会使用statement格式记录到binlog。

总结

今天主要就分享了MySQL中binlog的三种格式对比,希望对大家有所帮助

参考

《MySQL实战45讲》

以上是关于MySQL的binlog日志的主要内容,如果未能解决你的问题,请参考以下文章

MySQL清理binlog日志的方法

mysql 利用binlog日志恢复问题

mysql binlog日志说明及设置

Mysql之binlog日志说明及利用binlog日志恢复数据操作记录

mysql开启binlog日志

MySQL binlog日志恢复数据