情况:
PostgresSQL数据库。使用SQL Alchemy ORM的应用程序(不是很重要)。具有数百万行的表。
数百个进程使用该表访问数据库。每个人都希望选择一行并根据其内容执行相对昂贵的操作,然后填充其他表并更新该行。
我使用的天真的方法是这样的:
SELECT * FROM table WHERE status = 'free';
,然后紧接着:
UPDATE table SET status 'in_process';
现在的问题是这些操作不是原子操作,这意味着在SELECT
和UPDATE
之间的时间里,最多还有5个其他进程可以选择该行并开始处理(该行,我提醒您,它非常昂贵)。
现在我知道有SELECT FOR UPDATE
可以锁定行。但这会锁定它们FOR UPDATE
(duh),不会禁止选择行。
所以我想这肯定是一个非常普遍的问题,但是使用谷歌搜索并没有太大帮助。
答案 0 :(得分:0)
SELECT ... FOR UPDATE
是一种很好的技术,因为它们彼此阻塞,因此只有具有相同意图的其他人才能在完成交易之前获得您的行。
如果要忽略其他人锁定的行,则可以添加SKIP LOCKED
子句。
一种可能对您有吸引力的替代方法是
UPDATE atable
SET status = 'in_progress'
WHERE status = 'free'
RETURNING *;
答案 1 :(得分:0)
似乎是解决此问题的一种方法:
使用python和sqlalchemy(但这不是必需的,因为无论如何我都使用原始SQL)
from sqlalchemy import text
sql = text("UPDATE table
SET status = 'in_process'
WHERE column.id = (SELECT column.id
FROM table
WHERE status='free'
AND pg_try_advisory_xact_lock(column.id)
LIMIT 1 FOR UPDATE)
RETURNING *"
row = next(iter(engine.execution_options(autocommit=True).execute(sql)))
# Now row is a tuple of values