如何设计数据库归档、冷热分层与数据生命周期
不要把归档当搬老数据;先解释“账目表 8 亿行后,为什么查询、备份、删除都变慢”
这一页只解决一个问题: 历史数据怎样有秩序地离开热库,同时仍然可查、可审计、可删除证明。归档不是备份,也不是软删除,而是数据库生命周期设计。
Web 记账系统跑了三年,ledger_entries 从 50 万行变成 8 亿行。新增账目还能跑,但月报导出慢、备份窗口拖到白天、删除租户跑几个小时,磁盘持续报警。
| 第一反应 | 为什么不够 | 逼出的设计 |
| 继续加索引 | 写入和存储成本继续升高 | 热数据和历史数据要分层 |
| 扩容磁盘 | 备份、恢复、扫表窗口仍然变长 | 容量不是唯一问题 |
| 直接删一年前数据 | 用户、审计、纠纷可能仍要查 | 先定义保留矩阵 |
| 问题 | 例子 |
| 什么数据必须在线 | 近 90 天账目、当前预算、最近导入批次 |
| 什么数据可以慢一点 | 一年前账目、年度报表、低频历史导出 |
| 什么数据只为审计保留 | 老审计日志、纠纷证据、历史附件 |
| 到期动作是什么 | 删除、匿名化、只保留聚合,不能混着说 |
| 归档后怎么查 | 热库查、归档库查、异步导出、审批审计查 |
| 副本在哪里 | 搜索索引、报表宽表、附件、缓存、备份也要进生命周期 |
retention_policy
- data_object
- hot_retention_days
- archive_retention_days
- terminal_action: delete | anonymize | aggregate_only
- exception_reason
- owner
archive_batch
- batch_id
- object_type
- range_start
- range_end
- source_count
- archive_count
- checksum
- status
吸收点: 归档要有政策和批次证据。没有保留矩阵的归档脚本,只是在凭感觉搬数据。
| 边界 | 不能混成什么 | 正确理解 |
| 软删除 | 不等于归档 | 只是状态,仍占热库、索引和备份 |
| 归档 | 不等于合规删除 | 数据仍存在,只是换了访问路径 |
| 备份 | 不等于归档 | 备份为事故恢复,归档为长期低频访问 |
| 分区 | 不等于自动变快 | 只有查询带分区键,分区裁剪才有效 |
关键边界: 用户数据只要还能从主库、索引、附件、报表或备份中被查到,它就还在生命周期里。
| 样本 | 通过标准 |
| 归档某租户 24 个月前账目 | 行数、金额合计、checksum 对得上 |
| 用户查三年前账目 | 能走历史查询或异步导出,不让用户猜路径 |
| 归档脚本中断 | 按 archive_batch 续跑,不重复、不漏 |
| 主表删除后搜索仍能搜到 | 墓碑事件或索引重建能清掉副本 |
| 用户注销要求删除 | 能说明已删、匿名化、保留例外和备份窗口 |
| 从归档恢复一批数据 | 能拉到隔离环境并通过业务校验 |
如果 archived / deleted 是业务状态
总结: 数据库归档的核心不是“老数据搬走”,而是按访问价值、保留责任、查询体验和副本清单设计退场。软删除、归档、备份、合规删除必须分清。