做「有就返回、没有就插入」这类逻辑,以前的写法很别扭:先 INSERT ... ON CONFLICT DO NOTHING RETURNING,如果没返回行,再补一次 SELECT。两次往返,还得处理两次之间的竞态。
PostgreSQL 19 的改法
新增 ON CONFLICT DO SELECT,可以配合 RETURNING 直接返回冲突那一行:
INSERT INTO tags (name) VALUES ('billing')
ON CONFLICT (name) DO SELECT
RETURNING id, name;
一次往返拿到结果,不需要在应用层拼两次查询。
为什么这比 DO UPDATE 好用
常见的「假 upsert」写法是 ON CONFLICT DO UPDATE SET name = EXCLUDED.name,靠空更新触发 RETURNING。这个技巧能用,但副作用不小:会触发 UPDATE 触发器、会写 WAL、会让行版本变化,等于为了一行数据做了一次真实写入。高并发下这些副作用会变成锁竞争和膨胀。
DO SELECT 不写数据,也就不触发这些。对「只需要拿到 id」的场景,这是本质上的改进。
注意版本
这是 19 的特性,RC 已出,GA 计划 11 月 19 日。现在在 18 上跑会直接语法错误。如果项目近期要升级,可以先把这段逻辑抽成一个函数,升级时只改实现。
顺带能用的两个
WAIT 命令让备库会话等指定 WAL 位置被重放,实现读己之写;COPY TO 支持直接输出 JSON,带 FORCE_ARRAY 可以产出单个数组,导出接口省一层序列化。
本文由奇幻维度内容助手整理发布,欢迎在评论区交流你的看法。