用错 Binlog 模式,可能会导致 MySQL 的数据不一致性、性能下降、存储空间浪费和数据恢复困难等问题。
在 MySQL 中,不管使用什么存储引擎,只要表数据更新,就会产生 Binlog(归档日志)。
而 MySQL 数据库的数据备份、主备、主主、主从等实现,也离不开 Binlog(归档日志)。

针对不同的应用场景,Binlog 推出了三种工作模式 Statement、Row、Mixed,以满足对数据库的需求。
大家好,我是宝妹儿。
今天我们就来深入 Binlog 的三种模式,包括它的原理、优缺点、适用场景、配置管理、切换方式等。
这也是 MySQL 的重要知识点及高频面试点,宝妹儿顺便将这个题目以及参考答案,已添加到2023版《MySQL 大厂高频面试题大全》PDF了,方便系统学习、面试通关。
宝妹儿精编的2023版《MySQL 大厂高频面试题大全》,已收录100+道真题,近30000字,会长期迭代、持续更新。
吃透它,应付MySQL面试没问题。
公众号Java面试题宝,回复关键字:mysql,即可获取。
在 MySQL 中,Binlog 是一种二进制形式记录的日志文件,用于记录数据库的修改操作,包括插入、更新和删除等。
Binlog 的 2 大作用:
数据恢复:如果 MySQL 意外停止,可以通过该日志进行恢复、备份;
数据复制:master 把它的二进制日志传递给 slaves ,从而实现 master-slove 数据的一致性。
Binlog 的 3 个模式:
为了满足不同场景下的MySQL需求,Binlog 推出了三种工作模式,分别是:Statement、Row、Mixed。
2.1 Statement 模式的概念
Statement 是基于语句的复制模式。
Statement 模式将数据库中执行的修改操作记录为 SQL 语句,再从数据库上执行相同的 SQL 语句来实现数据同步。
2.2 Statement 模式的优点
Statement 模式的优点是简单明了,易于理解和实现。
2.3 Statement 模式的缺点
Statement 模式在执行涉及非确定性函数、触发器和存储过程等操作时,可能会导致不一致的结果。
1)不支持 RU、RC 隔离级别;
2)binglog 日志文件中,上一个事物的结束点是下一个事物的开始点;
3)DML、DDL 语句都会明文显示;
4)对一些系统函数不能准确复制或者不能复制;
5)主库执行 delete from t1 where c1=xxx limit 1,statement 模式下,从库也会这么执行,可能导致删除的不是同一行数据;
6)主库有 id=1 和 id=10 两行数据,从库有 id=1,2,3,10 这四行数据,主库执行 delete from t1 where id<10 命令,从库删除过多数据。
2.4 Statement 模式的应用场景
Statement 模式适用于大多数情况下的数据库复制需求。
例如:
1)一次更新大量数据,如二十万数据。反之,在复制时,从库可能会追得太慢,然后导致延时;
2)使用 pt-table-checksum 工具时。
示例一:
update这个事物的开始是insert这个事物结束的点at1581;update结束的点是commit之后的点at1842;[root@Darren2 logs]# MySQLBinlog --start-position=1581 --stop-position=1842 MySQL-bin.000022;......BEGIN/*!*/;# at 1729#170408 14:40:49 server id 330622 end_log_pos 1841 CRC32 0xb443cf1e Query thread_id=55 exec_time=0 error_code=0use `testdb`/*!*/;SET TIMESTAMP=1491633649/*!*/;update t10 set c2='bbb' where c1=1/*!*/;# at 1841#170408 14:40:49 server id 330622 end_log_pos 1872 CRC32 0xd06c40f5 Xid = 1756COMMIT/*!*/;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*/;示例二:当查看commit之前的position点时,会看到rollback状态,说明这个截取的事物不完整:[root@Darren2 logs]# MySQLBinlog --start-position=1581 --stop-position=1841 MySQL-bin.000022;BEGIN/*!*/;# at 1729#170408 14:40:49 server id 330622 end_log_pos 1841 CRC32 0xb443cf1e Query thread_id=55 exec_time=0 error_code=0use `testdb`/*!*/;SET TIMESTAMP=1491633649/*!*/;update t10 set c2='bbb' where c1=1/*!*/;ROLLBACK /* added by MySQLBinlog */ /*!*/;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*/;
2.1 Row 模式的概念
MySQL 5.7 默认的日志模式为 Row。
Row 模式是基于行的复制模式,它将数据库中实际修改的行记录写入 Binlog ,从数据库通过解析 Binlog 来逐行执行相应的修改操作。
相对 statement ,Row 模式更加精确、安全,能够确保数据的一致性。
2.2 Row 模式的优点
Row 模式能准确复制修改的行记录,避免了语句复制模式下的不确定性问题。
2.3 Row 模式的缺点
如果 Binlog 文件较大,传输成本就会很高,在某些情况下,可能会导致性能下降。
1)在表有主键的情况下复制更加快;
2)系统的特殊函数也能复制;
3)更少的锁,只有行锁;
4)Binlog 文件比较大,假设单语句更新 20 万行数据,可能要半小时,也有可能把主库跑挂;
5)MySQL 5.6 之前的版本,无法从 binog 看见用户执行的 SQL 语句;
6)DDL 语句明文显示,DML 语句加密显示;
7)DML 经过 base64 加密,需要使用参数 --base64-output=decode-rows --verbose;
8)update 修改的语句可以看到历史旧数据。
示例:
开启Binlog_rows_query_log_events参数,会显示执行的SQL语句,这个参数默认关闭,不显示执行的SQLroot@localhost [testdb]>set Binlog_rows_query_log_events=on;[root@Darren2 logs]# MySQLBinlog -vv --base64-output=decode-rows MySQL-bin.000024......create table t10(c1 int,c2 varchar(50))# insert into t10 values(1,now())## INSERT INTO `testdb`.`t10`## SET## @1=1 /* INT meta=0 nullable=1 is_null=0 */## @2='2017-04-08 15:26:09' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */insert into t10 values(2,now())### INSERT INTO `testdb`.`t10`## SET## @1=2 /* INT meta=0 nullable=1 is_null=0 */## @2='2017-04-08 15:26:09' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */at 1033# insert into t10 values(3,sysdate())### INSERT INTO `testdb`.`t10`## SET## @1=3 /* INT meta=0 nullable=1 is_null=0 */## @2='2017-04-08 15:26:09' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */insert into t10 values(4,uuid())## INSERT INTO `testdb`.`t10`## SET## @1=4 /* INT meta=0 nullable=1 is_null=0 */## @2='a2b570b8-1c2c-11e7-bc58-000c29c1b8a9' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */update t10 set c2='bbb' where c1=1## UPDATE `testdb`.`t10`## WHERE## @1=1 /* INT meta=0 nullable=1 is_null=0 */## @2='2017-04-08 15:26:09' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */## SET## @1=1 /* INT meta=0 nullable=1 is_null=0 */## @2='bbb' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */
2.4 Row 模式的应用场景
Row 模式适用于对数据一致性要求较高的场景,特别是涉及一些复杂的数据库操作和业务逻辑。例如,涉及触发器、存储过程和函数等的数据库操作。
使用Row 模式时需注意,Row 模式可能导致 Binlog 文件较大,需要合理设置 Binlog 文件大小和保留时间。
3.1 Mixed 模式的概念
Mixed 模式(混合模式)是将语句复制模式和行复制模式结合起来使用。
大多数的修改操作,通常使用 Statement 模式记录对应的 SQL 语句。
一些特殊的操作,涉及非确定性函数和存储过程等,则使用 Row 模式记录修改的行记录。
3.2 Mixed 模式的优缺点
Mixed 模式综合了语句复制模式和行复制模式的优点,能够在大多数情况下高效地记录修改操作,并在需要时使用行复制模式确保数据的准确性。
但 Mixed 模式对一些特殊操作的处理可能会很复杂,需要特别注意下配置和管理。
简单总结下:
1)innodb 引擎,如果隔离级别是 RU、RC,则 Mixed 模式会转成 Row 模式存储。
示例:
set tx_isolation='read-committed';set Binlog_format='mixed';flush logs;create table t10(c1 int,c2 varchar(50));insert into t10 values(1,now());insert into t10 values(2,now());insert into t10 values(3,sysdate());insert into t10 values(4,uuid());update t10 set c2='bbb' where c1=1;[root@Darren2 logs]# MySQLBinlog -vv --base64-output=decode-rows MySQL-bin.000028......### UPDATE `testdb`.`t10`### WHERE### @1=1 /* INT meta=0 nullable=1 is_null=0 */### @2='2017-04-08 18:34:08' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */### SET### @1=1 /* INT meta=0 nullable=1 is_null=0 */### @2='bbb' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */......
2)在以下几种情况下,Mixed 模式会自动将 Binlog 的模式 SBR 转化成 RBR 模式:
当更新一个 NDB 表时;
当函数包含 uuid() 函数时;
2个及以上包含 auto_increment 字段的表被更新时;
视图中必须要求使用 RBR 时。
示例:
set tx_isolation='repeatable-read';set Binlog_format='mixed';flush logs;create table t10(c1 int,c2 varchar(50));insert into t10 values(1,now());insert into t10 values(2,now());insert into t10 values(3,sysdate());insert into t10 values(4,uuid());update t10 set c2='bbb' where c1=1;[root@Darren2 logs]# MySQLBinlog MySQL-bin.000029......update t10 set c2='bbb' where c1=1......
3.3 Mixed 模式的应用场景
Mixed 模式适用于大多数情况下的数据库复制需求,尤其适合需要兼顾效率和准确性的场景。
在使用 Mixed 模式时,需要注意对特殊操作进行测试和验证,确保数据的一致性和正确性。
4.1 查看 Binlog 模式
MySQL> show global variables like "%Binlog_format%"; +---------------+-----------+ | Variable_name | Value | +---------------+-----------+ | Binlog_format | STATEMENT |+---------------+-----------+
4.2 配置 Binlog 模式
vim my.cnf,在 MySQLd 模块中配置。
log-bin = /data/3306/MySQL-bin Binlog_format="STATEMENT"#Binlog_format="ROW" #Binlog_format="MIXED"
不重启,使配置在 MySQL 中生效。
SET global Binlog_format='STATEMENT';
4.3 Binlog 模式的切换方法
1) 修改配置文件
可以通过修改 MySQL 的配置文件来切换 Binlog 模式。
编辑 MySQL 的配置文件(通常是 my.cnf 或 my.ini ),找到 Binlog_format 参数,并将其设置为所需的模式。
Binlog_format = ROW
然后重新启动 MySQL 服务,使新的 Binlog 模式生效。
2) 使用 SQL 语句切换
另一种切换 Binlog 模式的方法,是通过执行 SQL 语句来修改 Binlog_format 参数。
SET GLOBAL Binlog_format = 'ROW';
这会立即将 Binlog 模式切换为指定的模式。
这种修改在 MySQL 服务重启后会失效,因此需要在重启前进行相应的配置修改。
3) 动态切换
MySQL 5.6 及以上版本提供了动态切换 Binlog 模式的功能,可以在不重启 MySQL 服务的情况下进行切换。
SET SESSION Binlog_format = 'ROW';
这将在当前会话中将 Binlog 模式切换为指定的模式。
动态切换只对当前会话有效,不会影响其他会话或 MySQL 服务重启后的配置。
通过本文,我们学习并掌握了 Binlog 三种模式 Statement、Row、Mixed,包括它们的特点、优缺点、应用场景,以及如何配置、切换等。
Binlog 模式选型思路参考:
使用 MySQL 特殊功能较少,例如存储过程、触发器、函数等,用 Statement 模式。
使用 MySQL 特殊功能较多,用 Mixed 模式。
使用 MySQL 特殊功能较多,同时希望数据最大化一致,用 Row 模式。
在实际应用场景中,请结合具体情况来合理选择。
