alter table在row模式下会产生巨量binlog,因其逐行构建索引或重建表,每行插入/删除均记为独立write_rows_v2或delete_rows事件;即使algorithm=inplace也强制记录,以保障主从一致性。

因为 ALTER TABLE 在 ROW 模式下不是记一条语句,而是把每一行数据写入新结构的过程,都当成独立 DML 记进 binlog。
ROW 模式下 ALTER TABLE 本质是逐行 DML
MySQL 在加索引、重建表(如 ALTER TABLE ENGINE=InnoDB 或 OPTIMIZE TABLE)时,并非原子性 DDL 操作。它实际会创建临时表,再把原表数据一行一行读出、转换、插入到新表或新索引结构中。在 binlog_format=ROW 下,每行 INSERT 都生成一个 Write_rows_v2 事件;每行 DELETE(旧表清理阶段)也对应一个 Delete_rows 事件。
常见错误现象:
- 一张 300 万行的表执行
ALTER TABLE ADD INDEX,binlog 新增体积超 1.2GB - 主库磁盘告警,
SHOW BINARY LOGS显示最近几个日志文件异常庞大 - 从库复制延迟飙升,
Seconds_Behind_Master持续增长
关键点:
- 即使用了
ALGORITHM=INPLACE,只要 binlog 开启且为 ROW 模式,仍强制记录每行变更(这是复制一致性的硬性要求) -
MIXED模式在此类操作中几乎总会 fallback 到 ROW,不能靠它“自动省日志” - STATEMENT 模式下,
ALTER TABLE本身可能不记 binlog,但部分版本或特定操作仍会触发 row 级日志(尤其涉及隐式转换或分区表)
哪些 ALTER TABLE 操作最易触发 binlog 疯涨
不是所有 ALTER TABLE 都等量产日志。影响程度取决于是否引发全表扫描+行级重写:
- 高风险(必然大量 binlog):
ADD INDEX、DROP INDEX(二级索引重建)、ALTER TABLE ENGINE=...、OPTIMIZE TABLE、MODIFY COLUMN(类型变更需重写数据) - 低风险(通常无 binlog 或极少):
ADD COLUMN(末尾追加,InnoDB 8.0+ 支持 instant)、CHANGE COLUMN(仅改名,不改类型)、RENAME TABLE - 中等风险(取决于数据量和锁模式):
ADD COLUMN非末尾位置、SET DEFAULT(若触发全表更新)
性能影响:
- binlog 写入本身增加 fsync 压力,可能拖慢
ALTER TABLE执行速度 - 网络带宽占用激增,主从间传输延迟放大
- binlog 文件碎片化,
PURGE清理变慢,SHOW BINARY LOGS查询响应延迟
临时规避 binlog 疯涨的实操手段
生产环境不能直接关 binlog,但可在可控范围内绕过日志记录路径:
- 对单机或明确可手动补建索引的场景:执行前先运行
SET SESSION sql_log_bin = 0,再做ALTER TABLE(注意:该 session 的所有 DML 也不记 binlog) - 对大表,优先用
pt-online-schema-change:它通过影子表 + 触发器实现增量同步,binlog 压力摊到数小时窗口,避免集中爆发 - 禁止在业务高峰执行;提前检查
binlog_expire_logs_seconds是否设置合理(推荐设为 604800,即 7 天) - 切勿在主库上长期使用
SET GLOBAL sql_log_bin = 0—— 这会让从库彻底失联
容易被忽略的细节:哪怕你只是给空表加索引,MySQL 仍要全表扫描确认“无数据需写入”,这个扫描动作本身在 ROW 模式下也会产生极简的 binlog 事件(虽小但不可跳过)。真正的“零 binlog” DDL 几乎不存在,只能控制范围和节奏。











