site logo

Marico's space

PostgreSQL 18 来了,你们那份 NoSQL 迁移方案可以删了

服务器技术 2026-04-27 15:06:58 3

2025年9月25日,PostgreSQL 18 正式发布。如果你是在冲刺计划中间隙扫了一眼发布说明,然后把它归档为"小版本升级",建议回头再看看。这版本里落地的五件事,恰好就是你们团队 2023 年在 Confluence 上建的那个"可能需要把部分业务迁移到 Mongo / Dynamo / Cassandra"文档的五个理由。

现在你可以停更那个文档了。你当初标记的那些场景,大部分现在在 Postgres 里都有可行方案了——一套 schema、一套操作符、一套备份策略,全搞定。

异步 I/O:吞吐量这个话题可以重新聊了

这次最重头的功能是异步 I/O 子系统。Postgres 现在可以同时处理大量请求,Xata 和 Crunchy Data 报告在 NVMe 上能达到 2~3 倍的加速。

这个功能直接干掉的场景是:"我们需要 Cassandra 来处理写入密集型时序数据摄入"。有了 AIO,分析侧的扫描已经足够快,你不需要再维护第二套存储了。

但它干不掉的:真正跨区域的大规模水平扩展。AIO 是单节点层面的特性,别指望它来解决全球化问题。

UUIDv7:"我们用 Mongo 是因为 ObjectId"这个理由报废了

PG18 内置了 uuidv7() 函数。UUIDv7 在高位嵌入毫秒级时间戳,生成的 ID 天然按创建时间排序。这解决了 UUIDv4 主键最让人头疼的 B 树碎片化问题。

这个功能对应的典型场景是:"我们用 Mongo 是因为需要能在客户端生成 ID,不用每次都跟服务器往返"。Postgres 生成的 UUIDv7 同样能做到这一点,而且不需要引入另一套数据库。

JSON_TABLE + JSONB + GIN:大部分 Mongo 查询场景可以覆盖了

JSON_TABLE 在 PG17 就出现了,现在 PG18 里已经稳妥到可以上生产了。把 JSON_TABLE 和现有的 JSONB 操作符(@>、?、#>>)以及带 jsonb_path_ops 操作类的 GIN 索引结合起来,你就拥有了一个有索引的路径查询语言,在无 schema 文档场景下跟 MongoDB 有一战之力。

CREATE TABLE user_events (
  id uuid PRIMARY KEY DEFAULT uuidv7(),
  user_id bigint NOT NULL,
  event_type text NOT NULL,
  occurred_at timestamptz NOT NULL DEFAULT now(),
  props jsonb NOT NULL
);

CREATE INDEX user_events_props_gin ON user_events
  USING GIN (props jsonb_path_ops);

查询场景:"过去一天内,购物车总价超过 50 美元且设备是 iOS 的所有 checkout 记录"——

SELECT e.id, e.user_id, e.occurred_at, j.total, j.promo, j.os
FROM user_events e
CROSS JOIN LATERAL JSON_TABLE(
  e.props, '$' COLUMNS (
    total numeric PATH '$.cart.total',
    promo text PATH '$.promo',
    os text PATH '$.device.os'
  )
) AS j
WHERE e.event_type = 'checkout'
  AND e.occurred_at > now() - interval '1 day'
  AND e.props @> '{"device": {"os": "ios"}}'
  AND j.total > 50;

这个组合直接干掉的场景是:"我们需要 Mongo 是因为要灵活 schema"。JSONB 给过你灵活 schema、读取时类型投影、还有 GIN 索引。

但它干不掉的:文档结构差异极大、任何索引都帮不上忙的那些极端场景。

逻辑复制:终于有生产级的味道了

PG18 修掉了之前让逻辑复制用起来像 beta 功能的那些坑。生成列可以复制了,冲突会报在 pg_stat_subscription_stats 里,并行 apply 默认开启。

对应的典型场景是:"我们用 DynamoDB Streams 是因为 Postgres 的 CDC(Change Data Capture)太痛苦了"。现在逻辑复制是一等的 CDC 数据源,接上 Debezium 或者原生订阅者就能拿到变更流了。

仍然是 NoSQL 领地的情况:跨区域主动-主动写入场景。逻辑复制目前是主从模式,除非你在上面自己构建冲突解决逻辑。

一些小功能,积少成多

PG18 还有一堆小的改进,方向都一样:

  • 时间维度的主键和外键约束,可以表达"这个时间段内唯一"而不用应用层来检查
  • 虚拟生成列,读取时计算而非存储,节省空间
  • OAuth 认证官方支持
  • 多列索引上的 Skip 扫描,省去索引花活

单独拎出来哪个都不够震撼,但每个都去掉一个小理由——让你留在 Postgres 的理由又多了一条。

NoSQL 依然赢的地方,说实话就三处

  1. 全球规模的跨区域写入吞吐。如果你的写入场景真的需要在多个区域以个位数毫秒的本地延迟接受写入,DynamoDB Global Tables 和 Cassandra 的无主复制确实是为此而生的。
  2. 纯消防水管的写入场景,查询模式极简。如果你每秒摄入几十万条非结构化文档,读取模式就是"把用户 X 的所有数据都给我",那文档存储在原始吞吐上还是更强。
  3. 小团队的运维简单性。一个托管的 DynamoDB 表几乎不需要持续操心。

除了这三处,2026 年还要从 Postgres 搬出去的理由,大多是历史惯性,而不是真正的需求。

那 80% 怎么办?

回去重读你那份"想迁移到 NoSQL 的清单",逐条问自己一个问题:是跨区域写入吞吐吗?是的话继续规划。如果不是——是要灵活 schema、要客户端 ID、要 CDC 流、要快速时序读取——那就留下来,PG18 已经有你要的功能了。

真正无聊但价值巨大的收益在运维侧:一套数据库、一套备份工具、一套认证模型、一套你的分析师已经熟悉的查询语言。

无聊,但正确。

原文:https://dev.to/gabrielanhaia/postgres-18-just-made-80-of-your-nosql-migration-plan-pointless-g2a