已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
MySQL 8.0.32 / InnoDB,单主 32C128G(NVMe),innodb_buffer_pool_size=48G,innodb_purge_threads=4,innodb_log_file_size=4G。核心表 t_payment_flow(支付流水)约 3.2 亿行、.ibd 约 480GB,6 个二级索引(含 2 个按 created_at 的范围索引),白天 OLTP 写入 QPS 约 1200(INSERT 为主 + 少量状态 UPDATE),innodb_stats_auto_recalc 已关、ANALYZE 定时在 05:00 跑(我之前在统计信息漂移上踩过坑)。
每天凌晨 02:00–05:00 有一个归档任务:把 90 天前的流水从主表 DELETE 到冷存(Parquet),单批约 1200–1500 万行,持续 2.5 小时。
performance_schema 抓下来不是锁、不是 IO wait,是 MVCC 版本链遍历变长(Innodb_rows_read 跳了 3 倍,buffer pool 命中率仍 99.6%);SHOW ENGINE INNODB STATUS 里 History list length 峰值 280 万,DELETE 结束后 12 分钟才回落到 5 万以下;Data_free 在批删后累计涨了 38GB(碎片化),但 .ibd 文件没缩;innodb_purge_threads 4→8,History list 峰值降到 190 万,但点查 P99 只降了 3ms——说明瓶颈不是 purge 消费速率,是 DELETE 产生 undo 的速率超过了 purge 的稳态处理能力;created_at 范围切片 + 单事务 DELETE 100 万行:单事务 undo 膨胀到 1.2GB,批删结束后 25 分钟 History list 才清零,长事务卡 purge 的代价比预期高得多;innodb_change_buffering:对点查 P99 影响不明显(±2ms),排除了 change buffer 合并干扰;Innodb_purge_rows_removed 的 delta?undo log 文件大小?)?阈值怎么定?有没有一个「安全区间」可以让批删跑在 purge 稳态能力之内?DELETE ... WHERE id BETWEEN ? AND ? 按主键范围切片(避免二级索引扫描开销),或者先 ALTER TABLE ... PARTITION BY RANGE 然后 DROP PARTITION(但 3.2 亿行加分区的 DDL 代价怎么评估)?我想要的不是「建议调大 purge 线程」这种通用建议——上面已经试过了,效果有限。我关心的是在 DELETE 产生 undo 的速率和 purge 消费 undo 的速率之间找到稳态平衡点,以及批删窗口内如何实时观测这个平衡是否被打破。