跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

SQL中如何安全地删除海量历史日志_分区删除与表轮转策略

分区表删除比DELETE快,但必须确认分区键和执行计划,直接执行DELETE FROM logs WHERE dt。 分区表删除比 DELETE 快,但必须确认分区键和执行计划 直接
DELETE FROM logs WHERE dt 在亿级表上会锁表、生成巨量 WAL、拖垮主从同步。真正安全的做法是按分区裁剪——前提是表已按时间字段(如 dt
或
create_time
)做了范围/列表分区,且查询能命中分区键。 用
EXPLAIN
验证是否“Partition Elimination”:输出里要有
Partitions: p202212,p202211
这类明确提示,否则仍是全表扫描 MySQL 8.0+ / PostgreSQL / ClickHouse 支持
ALTER TABLE ... DROP PARTITION
,但语法差异大:
DROP PARTITION p202212
(MySQL) vs
TRUNCATE PARTITION p202212
(ClickHouse) PostgreSQL 的
pg_partitioned_table
系统视图可查当前分区结构,别靠猜 非分区表只能走 TRUNCATE + 重命名,但需绕过外键和复制延迟 如果日志表没分区,又不能停写,
DELETE
不可行,
TRUNCATE
又会阻塞所有 DML。这时得用“交换表”策略:建新空表 → 重命名旧表为备份 → 重命名新表为原名 → 异步删备份表。 MySQL 中
RENAME TABLE logs TO logs_bak_202405, logs_new TO logs
是原子操作,不锁原表读写 务必提前禁用外键检查:
SET FOREIGN_KEY_CHECKS = 0
,否则重命名失败 备份表删除必须在从库延迟 SHOW SLAVE STATUS 的
Seconds_Behind_Master
判断 别用
DROP TABLE logs_bak_202405
一步到位——先
OPTIMIZE TABLE logs_bak_202405
释放空间再删,避免磁盘 IO 突增 轮转策略要绑定应用层写入路由,否则新数据仍进旧表 光清老数据没用。如果应用还在往
logs
表写,下个月又爆满。轮转本质是让写入自动落到新表,核心在应用配置,不在数据库DDL。 用表名带时间后缀(
logs_202405
)时,应用必须根据当前日期动态拼接表名,不能硬编码
INSERT INTO logs
MySQL 分区表的
MAXVALUE
分区是陷阱:它会吞掉所有越界数据,导致本该进新表的数据滞留在旧分区,必须定期
REORGANIZE PARTITION
ClickHouse 的
ReplacingMergeTree
虽支持 TTL 自动删,但只清理数据不缩容,得配合
OPTIMIZE TABLE ... FINAL
手动触发合并 误删恢复依赖备份粒度,不是靠 binlog 回滚 分区
DROP
或
TRUNCATE
后,binlog 里只有 DDL 语句,没有逐行数据,根本没法按条件回滚。真要恢复,得看备份策略是否覆盖到具体分区。 物理备份(xtrabackup / pg_basebackup)必须包含被删分区对应的数据文件路径,例如 MySQL 的
./logs/#P#p202212.ibd
逻辑备份(mysqldump)若用了
--skip-triggers --skip-routines
,可能漏掉分区定义,还原后表是空壳 别信“删完立刻停服务就能从 binlog 恢复”——只要主库还在写,binlog 就持续滚动,定位精确位点极难 分区边界、应用写入路由、备份有效性,这三个点任何一个没对齐,删得再快也是埋雷。实际操作前,先在从库上用相同语句跑一遍,看
EXPLAIN
和磁盘 IO 变化。

相关文章