Postgresql
更新“最舊”行
我需要更新數據庫中的“最舊”行(目前,它的限制為 1,但我還需要能夠將其設置為
n
)。我本質上是在持續不斷地“更新最舊的行並同時檢索它們”。
該列被索引,它被呼叫
last_sent_at
,我每分鐘呼叫它約 20K 次。問題是,
last_sent_at
可以NULL
,而且應該總是比時間充裕的更受青睞。填寫完所有內容後,應選擇“最舊的”。這對我有用,問題是我不知道它是否有效,而且當我需要一次更新 5 行時它也不起作用。我想我可以使用
IN
我只是擔心它會效率低下。UPDATE subscribers SET last_sent_at = '2018-11-17 00:02:27' WHERE id = ( SELECT id FROM subscribers ORDER BY last_sent_at NULLS FIRST LIMIT 1 ) RETURNING id;
如果表很大,性能的關鍵是
(last_sent_at NULLS FIRST)
.由於您要更新這麼多,因此請進行激進的
VACUUM
設置。這可以根據每張桌子進行調整。看:僅對於單行,
UPDATE
使用像您這樣的子查詢就可以了。對於N > 1
LIMIT N
,CTE 是您的安全賭注。像:WITH cte AS ( SELECT id FROM subscribers ORDER BY last_sent_at NULLS FIRST LIMIT 5 ) UPDATE subscribers s SET last_sent_at = '2018-11-17 00:02:27' FROM cte WHERE s.id = cte.id RETURNING id;
如果您在並發寫入負載下執行此操作,請向您添加另一個表達式以
ORDER BY
使順序確定。並將相同的表達式添加到您的索引以進行匹配!(可以有很多行NULL
,對嗎?)並且對在同一個表中獲取行鎖的所有命令使用相同的順序。否則,您可能會面臨多個事務以任意順序獲取鎖的死鎖。更好的是,FOR UPDATE SKIP LOCKED
如果您不受嚴格順序的約束,請使用。密切相關,有深入的解釋:有關的: