Postgresql

更新“最舊”行

  • November 18, 2018

我需要更新數據庫中的“最舊”行(目前,它的限制為 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 > 1LIMIT 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如果您不受嚴格順序的約束,請使用。密切相關,有深入的解釋:

有關的:

引用自:https://dba.stackexchange.com/questions/222765