bigywater.tech
MySQL / InnoDB · 94

Row-Based Binlog

跑一条真实的UPDATE语句,用mysqlbinlog解码对应的binlog事件,看row-based复制里真实存的到底是SQL还是数据。

0条SQL文本
binlog里真实找不到原始的UPDATE语句
2组行数据
改前(WHERE)和改后(SET)真实的完整列值

做的事:跑一条真实的UPDATE,去binlog里找它的真身

代码UPDATE shop.orders SET qty = 99 WHERE item='apple'; $ mysqlbinlog --base64-output=decode-rows -v source-bin.000003

验证:binlog里真实没有这条SQL语句,只有真实的行数据

实测 · 本机mysqlbinlog真实解码输出
### UPDATE `shop`.`orders`
### WHERE
###   @1=1
###   @2='apple'
###   @3=10
### SET
###   @1=1
###   @2='apple'
###   @3=99

这段真实解码出来的内容里,完全找不到UPDATE shop.orders SET qty = 99 WHERE item='apple'这句SQL文本——binlog里真实记录的是WHERE部分(改之前这一行的完整数据:id=1, item='apple', qty=10)和SET部分(改之后的数据:id=1, item='apple', qty=99),两组真实的列值快照,而不是导致这次修改的SQL语句本身。

结论:row-based复制真实换来的是确定性,代价是体积

这正是binlog_format=ROW(MySQL 8.0起的默认值)的真实核心特征:不管这条UPDATE语句本身写得多复杂(用了NOW()、RAND()、子查询、还是依赖某个session变量),binlog里真实存的都是它执行完之后、具体影响到的每一行的真实前后数据——这样replica重放时真实不需要重新计算这条语句(它甚至看不到原始语句),只要把这组行数据真实原样应用上去,结果必然和source一致,彻底避免了老式binlog_format=STATEMENT模式下"同一条SQL在source和replica上执行结果可能不一样"(比如用到了非确定性函数)这类真实的一致性风险。代价是显而易见的:一条只改了一行的UPDATE,如果这一行本身很宽(很多列、很长的字段),行镜像会比对应的SQL文本大得多——这正是下一篇binlog_row_image要解决的问题。

分步演示:从一条UPDATE到binlog里真实的行镜像

每一步都是本文上面用真实mysqlbinlog解码跑出来的原始结果。

binlog里藏的真实是数据,不是SQL
这一步新揭示的内容

    本文用到的工具

    • 本机真实的复制实验环境,mysqlbinlog --base64-output=decode-rows -v真实解码binlog事件
    • binlog_format=ROW(MySQL 8.0起的默认值)
    京ICP备2026067502号-1京公网安备11010502063487号