根据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;
文章提到了不正确的顺序,但我真的可以申请我的用例是否会在添加/删除时获得正确的结果。
答案 0 :(得分:0)
是的,您的查询可能会返回错误的结果。
见这个例子:
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)
这是因为查询在锁定之前返回标识的行,但显示的值是锁定成功后的当前值。