【问题标题】:PostgreSQL upsert (INSERT ON CONFLICT DO UPDATE) updates row even when it shouldn'tPostgreSQL upsert (INSERT ON CONFLICT DO UPDATE) 更新行,即使它不应该
【发布时间】:2023-02-04 01:57:01
【问题描述】:

我一直在尝试使用 PostgreSQL upsert 来更新值,以防此类行已经存在。在我的用例中,新值很可能与现有值完全相同,所以我想确保不会执行任何更新(也就是说 - 不会创建具有更高 xmax 版本的新行)如果值是相同的。我试过为此使用 IS DISTINCT FROM 子句,虽然它在常规更新语句中按预期工作(xmax 对于无效的更新保持不变),但在 upsert 表达式中使用时它似乎仍然会创建新行.

请考虑以下示例:

  1. 创建测试表:
    create table upsert_test (id integer, name text, primary key (id));
    
    1. 插入行并获取其xmax版本:
    insert into upsert_test (id, name) values (1, 'hello');
    select *, xmax from upsert_test;
    
    1. 执行无效的更新。观察 xmax 在每次执行时(意外地)递增:
    insert into upsert_test (id, name) values (1, 'hello')
    on conflict on constraint upsert_test_pkey do update
    set name = excluded.name where upsert_test is distinct from excluded;
    
    select *, xmax from upsert_test ;
    

    这是预期的行为吗?有没有办法阻止 PostgreSQL 为这种情况创建新行?

【问题讨论】:

  • xmax是最高的完成交易ID,所以每次交易后修改是绝对正常的...xmax不是表upsert_test的数据的一部分

标签: sql postgresql upsert


【解决方案1】:

如果您也查看 ctid,您会发现该值没有改变,所以该行仍然相同。 xmax was changed because the row was locked 操作中。

该行未更新,但被修改,该修改将导致 WAL 写入并弄脏该行的块,从而导致写入。这对你来说可能是不幸的,但没有办法解决它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-02
    • 2016-07-21
    • 2020-11-29
    • 1970-01-01
    • 2021-02-16
    • 2017-02-07
    • 2017-05-28
    • 1970-01-01
    相关资源
    最近更新 更多