开启binlog本身性能开销约1%,真正拖慢的是参数不匹配和大事务:sync_binlog=1未配组提交导致每事务刷盘、binlog_cache_size过小引发磁盘临时文件、大事务未拆分造成锁阻塞和主从延迟。

开启 binlog 本身不会让 MySQL 性能明显下降——官方实测开销约 1%,真正拖慢的,是背后那几组没配对的参数和没拆开的大事务。
sync_binlog=1 但没配组提交,等于每笔事务都强制刷盘
设了 sync_binlog = 1 却没启用组提交,MySQL 就没法把多个事务的 binlog 合并写入一次磁盘。结果就是:每个 COMMIT 都触发独立的 write() + fsync(),锁竞争暴涨,大量线程卡在 Writing to binlog 状态。
-
binlog_group_commit_sync_delay默认是 0,等于关闭攒批逻辑;建议从 100 微秒(100)起步,别直接设毫秒级 -
binlog_group_commit_sync_no_delay_count别乱调大,10~50 是线上稳妥值;设太大(比如 1000)会导致低流量时事务无故卡住 - 必须确保
innodb_flush_log_at_trx_commit = 1,否则两个刷盘节奏错开,组提交根本凑不起来
binlog_format=ROW 但 binlog_cache_size 太小,频繁落临时文件
用 ROW 格式记录变更,单条 UPDATE 影响 1000 行,binlog event 体积就可能超默认的 32KB 缓存。一旦溢出,MySQL 创建 ML 开头的临时磁盘文件,所有后续 COMMIT 都得排队等 LOCK_log 锁——这不是慢,是串行阻塞。
- 查
SHOW GLOBAL STATUS LIKE 'binlog_cache_disk_use',如果接近binlog_cache_use,说明几乎每个事务都在刷盘 -
binlog_cache_size建议按平均事务大小设为20971520(20MB)起,但别盲目拉到 512MB,单连接内存暴涨容易 OOM -
max_binlog_cache_size是熔断值,超了直接报错ERROR 1197 (HY000),它不加速,只防崩
大事务没拆分,COMMIT 前 binlog 全憋在内存里
一个百万行的 UPDATE 执行完,只要没 COMMIT,所有 binlog event 就一直卡在内存缓存中。主库看似“执行完了”,但从库一条日志都收不到;更糟的是,这个事务还长期持有行锁或 MDL 锁,其他 DML/DDL 全被堵死。
- 别用
LIMIT OFFSET分页更新,OFFSET 越大扫描越慢,且并发下极易漏数据或重复处理 - 安全拆法是用单调字段游标:每次取上一批最大
id,下一批用WHERE id > ?,配合索引保证范围可收敛、可验证 - 每批控制在 500~2000 行;太小收益低,太大易触发锁升级、undo 日志膨胀
最容易被忽略的一点:binlog_cache_size 是线程级私有内存,事务处于 Sleep 状态但没提交,照样霸占着缓存和可能已生成的 ML 临时文件,持续消耗 IO 资源——监控时得连 INFORMATION_SCHEMA.INNODB_TRX 一起看,不能只盯 binlog 文件大小。











