知识卡片

UPSERT:用一次原子操作消除"存在则更新"的竞态窗口

普通读书笔记卡

内容

PostgreSQL通过INSERT...ON CONFLICT语法(俗称UPSERT)把”判断记录是否存在、再决定插入还是更新”这个原本需要应用层先查询再判断的两步操作,收敛成数据库内部一次原子操作完成——写入时若命中唯一约束(如主键重复)自动转为UPDATE,不冲突则正常INSERT。这解决的是大量业务场景里”存在则更新、不存在则插入”的常见写入模式:如果由应用层自己拆成”先查、后写”两步实现,在并发场景下天然存在竞态窗口——两个请求同时查到”不存在”后都尝试插入,其中一个会失败甚至产生脏数据;把这个判断收进数据库一次操作内完成,从根本上消除了这个竞态窗口,代价是业务方需要提前在冲突列(通常是主键或唯一索引)上明确声明。这类”把多步判断收敛为数据库单次原子操作”的思路,对任何存在”先查后写”竞态隐患的写入场景都有参考价值。

参考来源

- 位置:《高可用架构(第1卷)》第6章《大数据与数据库》"6.10 从Postgres95到PostgreSQL9.5:新版亮眼特性"节,"6.10.3 PostgresSQL9.5的亮眼特性"(源文件:_epub-src/OEBPS/Text/Chapter6_10_4.xhtml) - 结论依据:原文说明"INSERT...ON CONFLICT,also known as'UPSERT'……可以看到由于x是主键,因此第2次INSERT INTO无法插入成功……可以看到上图中的INSERT失败后,进行UPDATE……如:在进行SQL语句编写时,我们经常会遇到大量的同时进行Insert/Update的语句,也就是说存在记录时,就更新(Update),不存在数据时,就插入(Insert)",直接支撑本卡片结论。 - 原始内容:INSERT...ON CONFLICT,also known as"UPSERT"……我们经常会遇到大量的同时进行Insert/Update的语句,也就是说存在记录时,就更新(Update),不存在数据时,就插入(Insert)。