【问题标题】:Using Postgres SQL, what is the fastest transaction to emulate an UPSERT for a single row?使用 Postgres SQL,为单行模拟 UPSERT 的最快事务是什么?
【发布时间】:2011-06-21 13:12:10
【问题描述】:

这个问题是关于单行的,而不是一组。我只是好奇使用最新最好的 Pg (9.0) 版本更快,以及为什么:

基于 PKEY 上的 SELECT 的条件 UPDATE 或 INSERT

尝试插入,在失败时捕获异常并回退到更新

尝试更新,在失败时捕获异常并回退到插入

我认为因为这取决于数据集,所以我们假设三种情况:

  • 50% 的行存在,50% 不存在
  • 存在 100% 的行
  • 100% 的行不存在

Presence 表示 PKEY 已满足并且应该更新该行。任何有关这方面研究的链接都会很棒。

【问题讨论】:

  • MERGE 是 ANSI-2003 语法:wiki.postgresql.org/wiki/SQL_MERGE
  • MERGE 还没有在 Postgresql 中。
  • RhodiumToad 补充说选项 1 具有隐式竞争条件,并且没有不涉及异常处理的解决方案。
  • 其实他们都有竞争条件。如果您采用其中任何一种方法,并在两个不同的窗口中一次运行一行,您的 upserts 中可能会出现错误。
  • 第一个“基于 PKEY 上的 SELECT 的条件 UPDATE 或 INSERT”是一种执行 upsert 的无效方式。 @ScottMarlowe:如果在事务中完成,最后两个很好(有一些额外的逻辑涉及 while 循环以避免死锁)。

标签: sql postgresql merge upsert


【解决方案1】:

在 postgres 9.5 中,可以执行实际的 upsert:

http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=168d5805e4c08bed7b95d351bf097cff7c07dd65

INSERT [...] ON CONFLICT DO UPDATE SET [...] WHERE [...]

【讨论】:

    【解决方案2】:

    第一种情况永远不会比其他两种更快,因为您首先发出的 SELECT 是不必要的额外工作,并且由 UPDATE(可能还有 INSERT)隐式完成。

    即使使用 50% / 50% 的分布,我认为使用 UPDATE/INSERT 会稍微快一些,因为错误处理(捕获异常)比不更新任何内容的 UPDATE 花费的时间要多得多。

    所以我会选择 UPDATE/INSERT 模式,除非您知道确实有 lot(例如 > 70%)的行不会存在。

    但只有在您的环境中进行良好的性能测试才能说明这一点。

    【讨论】:

    • 这正是我所期待的那种回应,我要让它静置一天才接受。
    • 只有在 >90% 的时间该行不存在的情况下,我才会先尝试插入。 - RhodiumToad #postgresql
    • 为了安全起见,您可能最终会编写 UPDATE/INSERT,然后通过再次执行 UPDATE 来捕获 INSERT 上的错误,即结合这两种方法。这应该可以正确处理针对相同数据的两个并行任务。想必您也需要创建一个保存点来有效地捕获 INSERT 异常?
    • 啊,再次阅读文档,看起来 plpgsql 自动处理创建保存点作为 begin..exception..end 构造的一部分
    猜你喜欢
    • 2020-01-09
    • 2019-09-24
    • 2011-04-09
    • 2022-02-04
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 2011-03-16
    • 1970-01-01
    相关资源
    最近更新 更多