DDL操作必须写入binlog,因其承担数据库元数据变更的逻辑同步职责,确保主从复制一致性、GTID对齐及备份位点可靠性;不记录将导致从库结构失配、复制中断或数据分裂。

DDL 操作(如 ALTER TABLE、DROP DATABASE)在 MySQL 中必须写入 binlog,否则主从复制和崩溃恢复会直接断裂——这不是可选项,而是 binlog 作为逻辑日志的底层契约。
DDL 语句为什么必须进 binlog?
binlog 的核心职责是记录“数据库状态如何被改变”,而 DDL 改变的是表结构、索引、分区等元数据,这些变更直接影响后续所有 DML 的语义。如果 ALTER TABLE t ADD COLUMN c INT 不写 binlog,从库就永远不知道这张表多了一列,后续往 c 插入数据时会报错或静默丢弃。
更关键的是:MySQL 主从复制依赖 binlog 重放来保持逻辑一致性。DDL 是原子性事件,它本身就是一个独立事务(即使没显式 BEGIN),必须以完整事件形式落盘,否则 IO 线程读到一半、SQL 线程执行失败,就会卡在中继日志里,造成复制中断。
DDL 在 binlog 中怎么记录?
不同 binlog_format 下处理方式不同:
-
STATEMENT:直接记录原始 SQL,比如ALTER TABLE t ENGINE=InnoDB;但遇到CREATE TABLE ... SELECT这类非确定性语句,可能在从库执行结果不一致 -
ROW:DDL 本身不走 row 格式(因为没“行变化”),MySQL 会自动降级为 statement 模式记录该事件,并打上GTID_LOG_EVENT或QUERY_EVENT标记 -
MIXED:由 server 自动判断,对 DDL 总是用 statement 方式记录
无论哪种格式,DDL 都会被封装成一个独立的 binlog event,且带有 Xid 或显式 COMMIT 标记,确保它和前后事务边界清晰。
不写 binlog 的 DDL 会出什么问题?
手动关闭 sql_log_bin=0 后执行 DDL,看起来快,但后果严重:
- 主库执行了
TRUNCATE TABLE t,从库表还在,主从数据逻辑已分裂 - 备份工具(如
mysqldump --single-transaction)依赖 binlog position 做一致性点,跳过 DDL 就会导致备份位点不可靠 - 使用 GTID 时,
sql_log_bin=0下的 DDL 不产生 GTID,从库无法跳过或对齐,复制线程直接报ER_NO_EXECUTED_GTID_SET - 某些 DDL(如
ALGORITHM=INSTANT)虽不锁表,但若未记 binlog,从库无法感知字段新增,INSERT 时会因列数不匹配失败
DDL 和 redo log 的提交顺序有影响吗?
没有。DDL 是 Server 层操作,它不经过 InnoDB 的事务路径,不写 redo log(除极少数元数据页更新外)。它的持久化只依赖 binlog 的 fsync 行为,由 sync_binlog 控制。也就是说:ALTER TABLE 成功返回,只代表 binlog 已刷盘(当 sync_binlog=1),不代表任何引擎层日志已落盘——但这恰恰说明 binlog 是 DDL 唯一可信的一致性载体。
真正容易被忽略的是:DDL 执行期间如果发生 crash,MySQL 重启后靠的是 data dictionary(mysql.ibd + INNODB_SYS_TABLES)恢复元数据,而不是 binlog 回放。所以 binlog 的作用不是 crash recovery,而是跨实例状态同步——这个边界必须分清。


















