数据从千万涨到亿级,历史数据到底该归档、分区、还是冷热分离?
帖子正文与楼层回复。
背景
做大数据平台这几年,我遇到的最频繁的架构讨论不是「怎么加索引」,而是「表越来越大,历史数据怎么办」。
一个很典型的场景:订单流水表从 2000 万涨到 1.2 亿行,单表 80GB+,80% 的数据是 3 个月以前的。日常业务查询 95% 集中在最近 7 天,但偶尔有运营要拉半年前的对账数据。这时候 DBA 说「该归档了」,业务说「别动我表」,架构师说「该冷热分离了」——三个人三个方向,吵一下午也吵不出结论。
我自己在两个项目里都碰过这个问题,最后选的方案不同,但决策过程高度相似,所以想抛出来聊聊。
常见分歧 / 几种做法
-
分区表(RANGE / LIST)派:按月或按季度建分区,查询走 partition pruning,冷分区可以单独管理(压缩、迁移到便宜存储)。优点是「表结构没变」,业务无感知;缺点是分区数有上限(MySQL InnoDB 建议 ≤ 8192),DDL 操作(加列、加索引)要逐分区或锁全表,而且分区键选择一旦定错(比如用 created_at 但业务按 order_id 查),pruning 完全失效。
-
冷数据归档到独立存储派:热数据留 MySQL,冷数据(>90 天)搬到对象存储(S3 / OSS)或 ClickHouse,需要查的时候走「归档查询网关」。优点是主库瘦身效果最明显,P99 直接砍半;缺点是引入了两套存储、两套查询路径,「查历史数据」从 200ms 变成 5~30s,业务体感差异大,而且回迁(把归档数据拉回热库)的成本经常被低估。
-
冷热分离(同引擎,不同磁盘/实例)派:热数据走 SSD 实例,冷数据走 HDD 实例或低配实例,通过中间件路由。优点是数据仍在关系型引擎里,查询语法不变;缺点是架构复杂度上去了,路由层本身成为单点,而且「冷」和「热」的边界是动态的(上个月冷、这个月可能又变热),路由规则要跟着数据访问模式调整。
-
分库分表 + 时间维度派:按时间分库(比如按季度一个库),老库整体降配。优点是隔离最彻底;缺点是这是单向门,拆了再合的成本极高,很多团队「提前拆」反而把自己坑了。
我的倾向与理由
我的默认顺序是:分区表 > 冷热分离 > 归档到独立存储 > 分库分表,核心判据不是「哪个性能最好」,而是可逆性和业务感知成本——
- 分区表:加分区、删分区都是 Online DDL,可回滚,业务 SQL 不用改,pruning 是确定性的(不依赖优化器估算)。这是「成本最低、收益最确定」的选项。
- 冷热分离:比分区多一层路由,但数据仍在同一个引擎,查询语法不变。适合「热/冷边界相对稳定」的场景。
- 归档到独立存储:收益最大但代价也最大(两套存储、两套运维、查询延迟跳变),适合「冷数据几乎不查」的极端场景。
- 分库分表:最后手段,数据量到 10 亿+ 且单库 IO 打满时才考虑。
但有一个前提我特别强调:在做任何选型之前,先拉数据访问模式的时间衰减曲线。具体做法:
-- 按天统计查询命中行数(从慢日志或 APM 聚合)
SELECT DATE(created_at) AS d,
COUNT(*) AS hit_rows
FROM t_order_flow
GROUP BY DATE(created_at)
ORDER BY d DESC
LIMIT 180;
如果 90% 的查询集中在最近 30 天 → 分区表足够; 如果 70% 在最近 7 天、20% 在 7~90 天、10% 在 90 天+ → 冷热分离更合适; 如果 99% 在最近 7 天、历史数据一年才查一次 → 直接归档到对象存储,别浪费 SSD。
想听大家
- 你们的「归档触发条件」是什么?是数据量到了某个阈值、还是查询 P99 劣化到某个程度、还是纯粹按时间(>N 天就搬)?
- 有没有「归档后业务突然要查 3 个月前的数据,结果等了 30 秒」被投诉的真实案例?你们怎么处理的?
- 分区表你们实际用到过多少个分区?有没有碰到 InnoDB 分区上限或 DDL 逐分区操作的坑?
- 冷热分离的路由层你们用的是什么(ProxySQL / 自研中间件 / 应用层判断)?路由判断的延迟开销大概多少?
欢迎带具体数字来聊:表多大、多少行、查询模式长什么样、最后选了什么、P99 从多少降到多少。越具体越有参考价值。