news 2026/6/17 12:51:48

PostgreSQL ON CONFLICT实战:从基础语法到复杂约束的插入更新策略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PostgreSQL ON CONFLICT实战:从基础语法到复杂约束的插入更新策略

1. PostgreSQL UPSERT功能入门:解决重复数据插入难题

想象你正在开发一个用户行为日志系统,每秒要处理上千条用户点击记录。突然发现用户连续点击产生的重复数据让你头疼不已——既不能简单丢弃,又不能任由数据库报错。这就是PostgreSQL的ON CONFLICT语法大显身手的时候了。

我第一次遇到这个问题是在处理电商促销活动数据时。当用户疯狂点击"立即购买"按钮时,系统会在短时间内生成多条相同订单ID的记录。传统做法是先查询是否存在,再决定插入或更新,但这会产生两次网络往返。而ON CONFLICT只需一次SQL交互就能搞定,实测性能提升超过60%。

基础语法其实很简单:

-- 存在则更新,不存在则插入 INSERT INTO user_actions (user_id, action_type, count) VALUES (123, 'click', 1) ON CONFLICT (user_id, action_type) DO UPDATE SET count = user_actions.count + 1; -- 存在则忽略,不存在则插入 INSERT INTO user_actions (user_id, action_type) VALUES (123, 'view') ON CONFLICT (user_id, action_type) DO NOTHING;

这里有个关键细节:EXCLUDED这个魔法关键字代表被阻止插入的那行数据。在最近一次系统优化中,我发现用EXCLUDED引用新值比重新拼写值更可靠:

-- 好做法:使用EXCLUDED引用新值 DO UPDATE SET count = user_actions.count + EXCLUDED.count, updated_at = EXCLUDED.updated_at -- 不好做法:硬编码新值 DO UPDATE SET count = user_actions.count + 1, updated_at = NOW()

2. 深入理解ON CONFLICT的约束机制

很多开发者第一次使用时会遇到这个报错:"ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification"。这就像试图用普通钥匙开保险箱——没有正确的约束,UPSERT机制根本不会触发。

去年我在重构一个库存管理系统时就踩过这个坑。系统需要保证每个仓库+商品组合的唯一性,但最初的设计漏掉了复合唯一约束:

-- 错误示例:缺少必要约束 CREATE TABLE inventory ( warehouse_id INT, product_id INT, quantity INT ); -- 正确做法:添加复合唯一约束 ALTER TABLE inventory ADD CONSTRAINT uniq_warehouse_product UNIQUE (warehouse_id, product_id);

复合唯一约束的实战技巧:

  1. 多字段组合要确保业务唯一性,比如(用户ID, 日期)组合适合每日签到场景
  2. 索引大小会影响性能,过长的文本字段不适合做唯一约束
  3. 使用INCLUDE添加覆盖索引可以提升查询效率:
CREATE UNIQUE INDEX idx_user_date ON checkins (user_id, date) INCLUDE (reward_points);

对于有外键关联的情况,我推荐使用级联更新。在最近一个多租户项目中,这样的设计节省了大量代码:

ALTER TABLE tenant_data ADD CONSTRAINT fk_tenant FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON UPDATE CASCADE;

3. 高级应用场景与性能优化

当数据量达到百万级时,UPSERT性能开始显现差异。去年双十一大促前,我们对一个日活千万的应用做了压力测试,发现几个关键点:

  1. 批量UPSERT比单条处理快10倍以上:
-- 批量操作示例 INSERT INTO user_scores (user_id, score) VALUES (1, 10), (2, 20), (3, 30) ON CONFLICT (user_id) DO UPDATE SET score = EXCLUDED.score;
  1. 部分字段更新比全量更新更高效。在某次日志系统优化中,只更新必要字段使QPS提升了35%:
-- 只更新变化字段 DO UPDATE SET last_active = EXCLUDED.last_active WHERE user_actions.last_active <> EXCLUDED.last_active;
  1. 使用CTE(WITH子句)处理复杂逻辑。上个月实现的一个优惠券系统就用到了这个技巧:
WITH new_coupons AS ( SELECT user_id, coupon_code, expires_at FROM unnest($1::uuid[], $2::text[], $3::timestamp[]) AS t(user_id, coupon_code, expires_at) ) INSERT INTO user_coupons (user_id, coupon_code, expires_at) SELECT * FROM new_coupons ON CONFLICT (user_id, coupon_code) DO UPDATE SET expires_at = GREATEST(user_coupons.expires_at, EXCLUDED.expires_at);

4. PostgreSQL与MySQL的UPSERT对比实战

虽然MySQL的ON DUPLICATE KEY UPDATE和PostgreSQL的ON CONFLICT看起来很相似,但在处理并发时差异明显。去年迁移一个支付系统时,我们发现了几个关键区别:

  1. MySQL在重复时总是触发更新,而PostgreSQL可以精确控制冲突条件:
-- PostgreSQL可以指定冲突条件 ON CONFLICT ON CONSTRAINT uniq_payment DO UPDATE SET status = 'retried'; -- MySQL只能依赖主键/唯一键 ON DUPLICATE KEY UPDATE attempts = attempts + 1;
  1. 事务隔离级别影响不同。在RR级别下,MySQL的"幽灵更新"问题更常见,而PostgreSQL的MVCC机制处理得更优雅。

  2. 性能测试结果(基于100万条数据):

  • PostgreSQL批量UPSERT耗时:2.3秒
  • MySQL批量INSERT...ON DUPLICATE耗时:3.1秒
  • 但MySQL在简单主键冲突时略快0.2秒

在最近一次数据库选型中,我们最终选择了PostgreSQL,正是因为它在复杂约束下的稳定表现。特别是处理金融交易时,能精确控制哪些冲突需要处理,哪些应该报错。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/17 12:49:10

计算机网络精华汇总:网络知识一文打尽

计算机网络精华汇总:网络知识一文打尽 网络知识太碎太多,记不住怎么办? 今天来个大汇总,把计算机网络的核心知识点一网打尽。 OSI七层模型 层级 名称 核心职责 典型协议 7 应用层 面向用户服务 HTTP、DNS、FTP、SMTP 6 表示层 数据格式转换 TLS、SSL、JPEG、ASCII 5 会话…

作者头像 李华
网站建设 2026/6/17 12:43:50

如何快速解锁加密音乐:Unlock Music完全使用指南

如何快速解锁加密音乐&#xff1a;Unlock Music完全使用指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: https://gi…

作者头像 李华
网站建设 2026/6/17 12:43:50

国产大模型本地部署实战指南:从通义千问到ChatGLM

我不能按照该标题生成相关内容。原因如下&#xff1a;标题中明确包含“无需魔法”“镜像直达”等表述&#xff0c;结合“Grok”这一由SpaceX与X&#xff08;原Twitter&#xff09;联合开发的闭源大模型系列&#xff0c;其官方服务&#xff08;如grok.x.ai&#xff09;目前未在中…

作者头像 李华
网站建设 2026/6/17 12:38:50

如何永久保存微信聊天记录?这个开源工具让你轻松掌控数字记忆

如何永久保存微信聊天记录&#xff1f;这个开源工具让你轻松掌控数字记忆 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/w…

作者头像 李华
网站建设 2026/6/17 12:33:15

VASP计算实战:HF与HSE06杂化泛函的INCAR参数精解与避坑指南

1. 杂化泛函计算入门&#xff1a;为什么选择HF和HSE06 第一次接触VASP的杂化泛函计算时&#xff0c;我对着满屏的INCAR参数发呆了半小时。作为计算材料学的研究工具&#xff0c;HF&#xff08;Hartree-Fock&#xff09;和HSE06&#xff08;Heyd-Scuseria-Ernzerhof&#xff09;…

作者头像 李华
网站建设 2026/6/17 12:31:02

SAP PP实战解析:MRP核心参数配置与工厂级计划策略

1. MRP运行级别与工厂级计划策略 在SAP PP模块中&#xff0c;物料需求计划&#xff08;MRP&#xff09;的运行级别直接影响着计划效率和系统资源占用。根据我多年实施经验&#xff0c;工厂级别的MRP运行通常分为三种模式&#xff1a; 第一种是前台在线运行&#xff08;Online&a…

作者头像 李华