上文分析的二进制日志实际上是基于STATEMENT格式的,下面我们来看看基于ROW格式的二进制日志,毕竟,两者对应的binlog事件类型也不一样,同时,很多童鞋反映基于ROW格式的二进制日志无法查到原生的DML语句,关于这个问题,其实官方也给出了解决方案,下面,将一一揭晓。
首先,来几条测试数据
MysqL> set binlog_format=row; Query OK,0 rows affected (0.00 sec) MysqL> flush logs; Query OK,1); font-weight: bold">0.01insert into test.t1 values(1,'a'); Query OK,1); font-weight: bold">1 row affected (use testDatabase changed
MysqLinto t1 2,1)">bupdate t1 set name=c' where id=2; Query OK,1)"> sec) Rows matched: 1 Changed: 1 Warnings: 0 MysqLdelete from t1 10.01 sec)
首先通过SHOW binlog EVENTS查看二进制日志中的内容
MysqL> show binlog events in MysqL-bin.000025; +------------------+-----+-------------+-----------+-------------+---------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | | MysqL-bin.000025 | 4 | Format_desc | 1 120 | Server ver: 5.6.31-log,binlog ver: | | Query 188 | BEGIN | Table_map 236 | table_id: 79 (test.t1) | Write_rows 278 79 flags: STMT_END_F | Xid 309 COMMIT /* xid=175 */ 381 429 471 502 xid=183 574 622 | Update_rows 672 703 xid=184 775 823 | Delete_rows 865 896 xid=185 17 rows in set (0.00 sec)
# MysqLbinlog MysqL-bin.000025
!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; !40019 SET @@session.max_insert_delayed_threads=0!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0; DELIMITER !; # at 4 #160817 10:20:16 server id 1 end_log_pos 120 CRC32 0x5b15ac4f Start: binlog v 4,server v 5.6.31-log created 16 # Warning: this binlog is either in use or was not closed properly. binlog ' 4MmzVw8BAAAAdAAAAHgAAAABAAQANS42LjMxLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAU+s FVs= '/*!*/; # at 12022 server 188 CRC32 0x005847f0 Query thread_id=12 exec_time=0 error_code=0 SET TIMESTAMP=1471400422; SET @@session.pseudo_thread_id=12; SET @@session.foreign_key_checks=1,@@session.sql_auto_is_null=0,@@session.unique_checks=1; SET @@session.sql_mode=1075838976; SET @@session.auto_increment_increment=!\C utf8 *//*; SET @@session.character_set_client=33,@@session.collation_connection=33; SET @@session.lc_time_names=; SET @@session.collation_database=DEFAULT; BEGIN 188236 CRC32 0x2b8d2069 Table_map: `test`.`t1` mapped to number 79 # at 236278 CRC32 0xadc98fbc Write_rows: table flags: STMT_END_F binlog 5smzVxMBAAAAMAAAAOwAAAAAAE8AAAAAAAEABHRlc3QAAnQxAAIDDwIeAANpII0r 5smzVx4BAAAAKgAAABYBAAAAAE8AAAAAAAEAAgAC//wBAAAAAWG8j8mt 278309 CRC32 0x552dc682 Xid = 175 COMMIT30934 server 381 CRC32 0x17d8173e Query thread_id=1471400434381429 CRC32 0x71a27e19 Table_map: `test`.`t1` mapped to number 429471 CRC32 0xefda98ca Write_rows: table 8smzVxMBAAAAMAAAAK0BAAAAAE8AAAAAAAEABHRlc3QAAnQxAAIDDwIeAAMZfqJx 8smzVx4BAAAAKgAAANcBAAAAAE8AAAAAAAEAAgACwCAAAAAWLKmNrv 471502 CRC32 0x7bed11c4 Xid = 18350238 server 574 CRC32 0xd164b750 Query thread_id=1471400438574622 CRC32 0x9fa3cabc Table_map: `test`.`t1` mapped to number 622672 CRC32 0xb1646398 Update_rows: table 9smzVxMBAAAAMAAAAG4CAAAAAE8AAAAAAAEABHRlc3QAAnQxAAIDDwIeAAO8yqOf 9smzVx8BAAAAMgAAAKACAAAAAE8AAAAAAAEAAgAC///8AgAAAAFi/AIAAAABY5hjZLE= 672703 CRC32 0x91a90c52 Xid = 18470343 server 775 CRC32 0x5ae24c0b Query thread_id=1471400443775823 CRC32 0x33c52e84 Table_map: `test`.`t1` mapped to number 823865 CRC32 0x77e907a2 Delete_rows: table ' +8mzVxMBAAAAMAAAADcDAAAAAE8AAAAAAAEABHRlc3QAAnQxAAIDDwIeAAOELsUz +8mzVyABAAAAKgAAAGEDAAAAAE8AAAAAAAEAAgACwBAAAAAWGiB+l3 865896 CRC32 0xb0988385 Xid = 185; DELIMITER ; # End of log file ROLLBACK added by MysqLbinlog !50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
额,what is this,竟然没看到一条明文的DML语句
实际上,对于ROW格式的二进制日志,需要使用如下方式查看,这也是STATEMENT和ROW格式的差异之一
# MysqLbinlog MysqL-bin.000025 -vv --base64-output=decode-rows
;
# at use or was not closed properly.
# at flags: STMT_END_F ### INSERT INTO `test`.`t1` ### SET ### @1=1 INT Meta=0 nullable=1 is_null=0 ### @2=a VARSTRING(30) Meta=30 nullable=1 is_null=0 */
79
2 b flags: STMT_END_F ### UPDATE `test`.`t1` ### WHERE ### @ ### SET ### @c flags: STMT_END_F ### DELETE FROM `test`.`t1` ### WHERE ### @;
DELIMITER ; # End of log */;
对于STATEMENT格式的binlog,所有的DML操作都记录在QUERY_EVENT中,而对于ROW格式的binlog,所有的DML操作都记录在ROWS_EVENT中,ROWS_EVENT分为三种:WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT,分别对应insert,update和delete操作。
对于insert操作,WRITE_ROWS_EVENT包含了要插入的数据
对于update操作,UPDATE_ROWS_EVENT不仅包含了修改后的数据,还包含了修改前的值。
对于delete操作,仅仅需要指定删除的主键(在没有主键的情况下,会给定所有列)
事实上,在ROW格式的binlog文件中, 每个ROWS_EVENT事件前都会有一个TABLE_MAP_EVENT,用于描述表的内部id和结构定义。
即便上述两个insert操作,一个没有执行use test操作,都不影响TABLE_MAP_EVENT的内容,这也会导致基于ROW格式下的库级别的复制和基于STATEMENT格式下库级别的复制的复制规则不一致。
如何在ROW格式中输出原生的DML语句?
MysqL实际上提供了一个参数,可以用于输出原生的DML语句,但是该语句仅仅是其注释的作用,并不会被应用。
如下所示,
对应的二进制的内容如下:
实际上,MysqL新增了一个事务类型来输出ROW格式中原生的DML语句,即ROWS_QUERY_EVENT。
自此以后,再也不用顾虑ROW格式的二进制日志中无法查看原生的DML语句了。
参考
1. MariaDB原理与实现
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。