Postgres 存储 JSON 字段(可能是 jsonb)数据量巨大,增长很快,长期占用 DB 存储,影响性能与成本。解决办法是 冷热分离 ——把大 JSON 存到对象存储(OSS/S3),数据库里只存元信息与引用。
方案设计
1. 存 OSS,不存 JSON 本体
-
OSS(阿里云 OSS、MinIO、S3 兼容存储等)擅长存储大对象、冷热数据。
-
Postgres 只保存:
- JSON 的 存储路径/Key(例如 oss://bucket/path/uuid.json)。
- JSON 的必要 摘要信息(比如大小、MD5、时间戳、业务主键)。
-
查询时通过 OSS SDK/API 取数据,不必压在 DB 内。
2. 表结构改造
原来:
CREATE TABLE data (
id BIGSERIAL PRIMARY KEY,
biz_id TEXT,
payload JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
改造后:
CREATE TABLE data (
id BIGSERIAL PRIMARY KEY,
biz_id TEXT,
payload_url TEXT, -- 存 OSS Key 或 URL
payload_md5 TEXT, -- 校验用
payload_size BIGINT, -- 记录大小
created_at TIMESTAMPTZ DEFAULT now()
);
3. 写入流程
-
应用接收 JSON。
-
生成唯一 key(如 UUID + 日期)。
-
JSON 压缩(gz 或 zstd)后上传 OSS。
-
OSS 返回 URL/etag,写入 Postgres payload_url 和相关元信息。
-
不再把大 JSON 放进 DB。
4. 读取流程
-
如果业务需要全量 JSON:
应用查 DB 拿到 payload_url → SDK 从 OSS 下载 → 解压后使用。
-
如果业务只需要部分字段:
-
可以额外存储一些 索引字段 在 DB,避免每次读 OSS。
-
比如 JSON 有 user_id, order_type,就可以拆出来单独建字段/索引。
-
5. 优化点
- 压缩:JSON 存 OSS 前可 gzip/zstd,大幅节省空间。
- 冷热分层:热数据(近 7 天)可以保留在 DB;超过一定时间归档到 OSS。
- 自动迁移:写一个定时任务,将老数据迁出 DB,只保留 URL。
- 查询场景考虑:如果经常需要对 JSON 内部字段过滤/聚合,最好在写入时 同步存索引字段,不然每次都得拉 OSS,很慢。
优缺点对比
✅ 优点
-
大幅降低 Postgres 存储压力,避免膨胀。
-
成本低:OSS 比 DB 存储便宜。
-
可以配合归档策略(冷热分层)。
⚠️ 缺点
- 查询复杂度高:不能直接 WHERE payload->>'field' = 'xxx'。
- 延迟:读大 JSON 需要额外 OSS IO。
- 需要应用层适配写入/读取逻辑。
可选方案
- pg_largeobject / TOAST 压缩:Postgres 自带,但仍然放在 DB,不解决膨胀问题。
- TimescaleDB + 外部存储插件:有些扩展支持外部文件存储。
- FDW(Foreign Data Wrapper)+ OSS:例如 postgres_fdw_s3,可直接把 OSS 当外部表。
要不要我帮你写一个 迁移脚本 Demo?比如:把 payload 里的 JSON 导出到 OSS,DB 字段替换成 oss_url,支持批量迁移老数据。