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的。这里我来说明一下为啥:
- 如果delete使用的是索引a,根据索引a找到第一条数据删除,也就是删除a=4这一行;
- 如果使用索引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
- Table_map event,用于说明接下来要操作的表是test库的t表
- 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日志的主要内容,如果未能解决你的问题,请参考以下文章