软删除、硬删除、还是归档?大表数据生命周期管理,你们团队到底怎么选
帖子正文与楼层回复。
背景
做了 10 年 DBA,被业务方问得最多的第二个问题(第一个是"表要爆了怎么办")就是:"这条数据能不能删?"
每次回答"能删",对方都要追问一句:"那万一以后要查呢?"——于是 is_deleted 字段就这么诞生了。然后三年后,那张表从 500 万行涨到 8000 万行,其中 75% 是 is_deleted = 1 的"尸体",每次查询都要多带一个 AND is_deleted = 0,索引里也多一列冗余,INSERT 和 UPDATE 的 B+ 树维护成本悄悄涨了 15%~25%。
三种常见做法,各有所长也各有代价
| 方案 | 做法 | 优势 | 代价 |
|------|------|------|------|
| 软删除 | is_deleted / deleted_at 标记,数据留在原表 | 可回溯、可审计、实现最简单 | 表无限膨胀、索引选择性下降、全表统计失真、查询必须带条件 |
| 硬删除 | DELETE 物理删除 | 表干净、索引紧凑、查询无额外条件 | 不可逆、审计依赖 binlog(但 binlog 有保留窗口)、误删无救 |
| 归档 | 定期把 N 天前的"冷数据"搬到归档表/冷存储 | 主表保持精简、归档数据仍可查、冷热分离 | 需要维护归档任务、跨表查询变复杂、归档表也会慢慢长大 |
我见过最极端的案例:一套 ERP 系统,"软删除"了 6 年,核心表 t_voucher(凭证)从设计时的 500 万行涨到 2.3 亿行,其中 is_deleted=1 占 82%。开发说"不敢删,审计要",DBA 说"不敢归档,查询要跨表",最终 P99 从 80ms 涨到 2.4s,最后花了 3 周做了一次"大迁移"才缓解。
我的倾向(带条件)
我倾向于默认软删除 + 定期归档的混合策略,但有一条硬规则:
- 软删除的保留窗口必须有限:
deleted_at不是"永不过期"的,默认 90 天。超过 90 天且无审计标记的,进归档队列。 - 归档不是"搬走就完事":归档表要有独立的索引策略(按时间分区、按查询模式建索引),并且提供统一的查询入口(视图或中间层),让业务代码不感知"这条数据在主表还是归档表"。
- 硬删除只用于"确定不可恢复"的场景:比如 GDPR 要求删除的用户数据、测试环境数据。生产环境的核心业务数据,我从不建议直接
DELETE。
但我也承认,对于日志型表(审计日志、操作记录),"只追加、不删除、按时间分区"可能是更优解——这类数据本来就没有"恢复"的需求,软删除是多余的复杂度。
想听大家聊聊
- 你们团队对"软删除保留多久"有没有明确的 SLA?还是"永远不删"?
- 归档表你们怎么建的?独立库、独立表、还是同库同表加时间分区?跨表查询怎么解决的?
- 有没有遇到过"软删除导致索引选择性崩溃"的案例?比如
is_deleted基数的分布让优化器选错索引? - 对于"审计合规要求保留 N 年"的场景,你们是把数据留在主表还是迁到专门的审计库?迁移时怎么保证查询不中断?
- 你们怎么衡量"归档任务"的性能影响?有没有在高峰期做归档然后被投诉的案例?
欢迎带具体数据来聊:表规模、删除比例、查询模式、存储成本——空谈方案没有意义,场景不同答案完全不同。