【问题标题】:PostgreSQL FOR UPDATE with ORDER BY and LIMIT interationPostgreSQL FOR UPDATE 与 ORDER BY 和 LIMIT 交互
【发布时间】:2018-02-21 15:30:33
【问题描述】:

根据https://www.postgresql.org/docs/9.5/static/sql-select.html

在 READ COMMITTED 运行 SELECT 命令是可能的 事务隔离级别并使用 ORDER BY 和锁定子句 乱序返回行。这是因为首先应用 ORDER BY。 该命令对结果进行排序,但随后可能会阻止尝试获取 锁定一个或多个行。一旦 SELECT 解除阻塞,一些 排序列值可能已被修改,导致这些行 似乎是无序的(尽管它们在 原始列值)。这可以通过放置在需要时解决 例如子查询中的 FOR UPDATE/SHARE 子句

SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1; 请注意,这将导致锁定 mytable 的所有行,而 FOR 顶层的 UPDATE 只会锁定实际返回的行。 这可能会产生显着的性能差异,尤其是 如果 ORDER BY 与 LIMIT 或其他限制结合使用。所以这 仅当同时更新排序时才推荐使用该技术 列是预期的,并且需要严格排序的结果。

在 REPEATABLE READ 或 SERIALIZABLE 事务隔离级别 这将导致序列化失败(SQLSTATE 为“40001”), 所以在这些条件下不可能接收到乱序的行 隔离级别。

假设我运行这个查询,

SELECT * FROM banks as x WHERE x.date < {inputDate} ORDER BY x.date DESC LIMIT 1 FOR UPDATE;

  • 假设行日期不能修改
  • 可以插入/删除银行行
  • 无论比赛条件如何,我每次都能安全地获得正确的结果吗?
  • 我检索到的单行会被 LOCK FOR UPDATE 吗? (我阅读了很多关于 LIMIT 和 FOR UPDATE 交互的资料,但仍然很困惑,有人可以确认这种情况下到底会发生什么吗?)

文章提到了错误的顺序,但我真的可以应用到我的用例中是否会在添加/删除时得到正确的结果。

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    是的,您的查询可能会返回错误的结果。

    看这个例子:

    CREATE TABLE banks (
       id integer PRIMARY KEY,
       date timestamp with time zone NOT NULL
    );
    INSERT INTO banks VALUES (1, '2017-09-01 00:00:00');
    INSERT INTO banks VALUES (2, '2017-09-01 01:00:00');
    

    现在,在一个会话中,我们启动一个更新一行的事务:

    BEGIN;
    UPDATE banks
       SET date = '2017-08-01 00:00:00'
       WHERE id = 2;
    

    然后,在另一个会话中,我们运行您的语句:

    SELECT *
       FROM banks AS x
       WHERE x.date < current_timestamp
       ORDER BY x.date DESC
       LIMIT 1
       FOR UPDATE;
    

    此会话将挂起,因为它试图用id = 2 锁定行。

    现在在第一个会话中,关闭事务:

    COMMIT;
    

    那么第二个会话就会解除阻塞并返回错误的结果:

    ┌────┬────────────────────────┐
    │ id │          date          │
    ├────┼────────────────────────┤
    │  2 │ 2017-08-01 00:00:00+02 │
    └────┴────────────────────────┘
    (1 row)
    

    这是因为查询返回锁定它之前标识的行,但显示的值是锁定成功之后的当前值。

    【讨论】:

    • 你如何像这样逐行运行postgre sql?我非常想这样做以进行调试。顺便谢谢你的帮助!
    猜你喜欢
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 2010-09-30
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多