binlog从格式上有两种格式,statement和row,还有一种存储模式为mixed,前两者混合的。

如何设置binlog的格式?

通过参数binlog_format设置

假设有这张表

  1. mysql> CREATE TABLE `t` (
  2. `id` int(11) NOT NULL,
  3. `a` int(11) DEFAULT NULL,
  4. `t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  5. PRIMARY KEY (`id`),
  6. KEY `a` (`a`),
  7. KEY `t_modified`(`t_modified`)
  8. ) ENGINE=InnoDB;
  9. insert into t values(1,1,'2018-11-13');
  10. insert into t values(2,2,'2018-11-12');
  11. insert into t values(3,3,'2018-11-11');
  12. insert into t values(4,4,'2018-11-10');
  13. insert into t values(5,5,'2018-11-09');

当执行以下删除语句时:

delete from t /*comment*/ where a>=4 and t_modified<='2018-11-10' limit 1;

statement

binlog记录的是SQL语句的原文。

内容查看

可以使用show binlog events in 'master_binlog.000001'查看binlog的内容
image.png

  • BEGIN和COMMIT对应,表示中间是一个事务
  • use test这条命令是MySQL自动添加的,保证从库去执行的时候能知道要操作哪个库
  • COMMT后面歇着xid,这个xid就是我们在MySQL日志系统文章中讲解的用来关联redo log和binlog的

    问题

    可能会导致主从数据不一致,因为statement格式是记录原来啊的SQL,从库也是去重放SQL,在这个语句中,
  1. 如果使用索引是a,那么会根据索引a找到第一个满足条件的行,也就是a=4
  2. 如果使用的索引是t_modified,那么删除的就是t_modified=’2018-11-09’也就是 a=5 这一行

因此从库重放会有风险。

通过show warnings可以看到MySQL的警告。

row

row格式会记录操作的主键id,从库重放也不会有问题。

内容查看

image.png
binlog中没有了原SQL,而是替换成了Table_map和Delete_rows

  • Table_map,用于说明接下来操作的表是test库的表t
  • Delete_rows,用于定义删除的行为

    详细内容查看

    需要借助mysqlbinlog工具:

    --start-position指定从这个位置的日志开始解析
    mysqlbinlog  -vv data/master.000001 --start-position=8900;
    

    image.png
    重要内容解析

  • server id 1,表示这个事务是在server_id=1的这个库上执行的

  • 每个event都有CRC32,是因为把参数binlog_checksum设置成了CRC32
  • @1、@2、@3表示的字段id、a、t_modified
  • binlog_row_image默认值为FULL,因此Delete_event里面,包含了删掉的行的所有字段的值,如果把binlog_row_image设置为MINIMAL,则只会记录必要的信息,在这个例子里,就只会记录id=4这个信息
  • 最后的Xid用于表示这个事务被正确地提交了

由于binlog记录了真实删除的行的主键id,这样binlog传到备库去的时候,就肯定会删除id=4这行,不会有主备删除行不一致的问题

mixed

由于row格式存储的内容过多,而statement又有可能会导致主从数据不一致,因此MySQL就取了一个折中的方案,MySQL自己会判断这条SQL语句是否可能引起主备不一致,如果有可能就用row格式,否则就用statement格式。

binlog_row_image

MySQL5.6新增的参数,默认值是FULL,binlog格式必须为row格式或者mixed格式
前镜像,即数据库表中修改前的内容。
后镜像,即数据库表中修改后的内容。

  • FULL,binlog日志记录所有前镜像和后镜像。
    • 如果数据出现误操作,可以通过flashback或者binlog2sql等快速闪回工具恢复数据
    • 在数据列比较大的情况下,在大量的update、delete操作时,binlog盘增长会很快
  • MINIMAL,binlog日志的前镜像只记录唯一识别列(唯一索引列、主键列),后镜像只记录修改列。
    • 可以节省不少磁盘空间,节省一定的IO,
    • 由于前镜像不记录修改列,只在后镜像记录修改列,如果数据出现误操作,必然不能通过flashback或者binlog2sql等快速闪回工具恢复数据
  • NOBLOB,binlog记录所有的列,就像full格式一样。但对于BLOB或TEXT格式的列,如果他不是唯一识别列(唯一索引列、主键列),或者没有修改,那就不记录。
    • 表中TEXT和BLOB等大字段如果不修改,就不记录前后的镜像了,其他小字段的列的修改依然记录前后镜像,一般大字段消耗的磁盘空间是非常大的,可以节省不少磁盘空间,如果表中没有大字段,NOBLOB和FULL格式并没有区别,如果数据出现误操作,可以通过flashback或BinLog2SQL等快速闪回工具恢复数据。