Postgresql

Postgres 事務下的鎖定問題

  • July 2, 2015

我最近收到“共享記憶體不足 - 您可能需要增加 max_locks_per_transaction”錯誤。

這是一個長時間執行的過程,我在正確處理後導入一堆 CSV 文件。我遍歷它們並為每個文件打開一個事務,處理它,然後當我完成文件時,關閉事務並移至下一個文件。

這些文件並不大,最大的大約 12K 行。

就 PG 而言,我所做的處理相當於做幾個SELECTs(每行幾個,沒有連接或任何東西),然後是UPDATE一個現有行(每行最多一個)。

問題是,pg_locks填充了沒有relation、類型transactionid和模式為 的事務ExclusiveLock。我有多達 20K 行這樣的行pg_locks,除了那些,正如預期的那樣,參考我正在使用的兩個表,絕大多數看起來像這樣(對不起,縮進會被搞砸,我正在發布一個指向 pastebin 的連結):

"locktype" "database" "relation" "page" "tuple" "virtualxid" "transactionid" "classid" "objid" "objsubid" "virtualtransaction" "pid" "mode" "granted" "fastpath"

"virtualxid" "" "" "" "" "11/18291" "" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "t"
"transactionid" "" "" "" "" "" "61840165" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61843843" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61833173" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61835511" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61846000" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61838308" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"
"transactionid" "" "" "" "" "" "61832936" "" "" "" "11/18291" "6308" "ExclusiveLock" "t" "f"

http://pastebin.com/V4K3AvHD

基本上,這些記錄都沒有數據庫或關係,只有事務 ID。

唯一不同的行是第一行,我認為它來自獲取自身鎖定的事務。

所有的鎖都是由同一個連接獲取的,顯然只有在執行時才可以UPDATE,這實際上並不比

UPDATE t SET foo = COALESCE(foo, 0) + 23.4 WHERE bar = 'hey' and baz = 'ho'

並且最多可以影響一行。

當我處理完文件並送出事務時,所有這數千條記錄都會從 中消失pg_locks,回到更正常的 15 到 30 條之間。就好像每條記錄都UPDATE以某種方式獲得了一個鎖,使記錄計數pg_locks增加每隔一兩秒調一個。

我想我一定做錯了什麼,但我不知道是什麼。

作為一種臨時解決方法,我確實增加了 max_locks_per_transaction,但我真的很想真正解決這個問題。我認為我的案例不需要增加 max_locks_per_transaction,這很簡單。

另外,請注意沒有其他人正在訪問我正在使用的兩個表。甚至沒有人訪問同一模式中的任何表。

我在 Windows Web Server 2008 R2 上。

PostgreSQL 9.3.5,由 Visual C++ build 1600 編譯,64 位

與 Npgsql 2.2.5 連接

任何人都可以解釋一下嗎?

我考慮過可能的索引問題,但是有問題的表無論如何都不大(少於 50K 行),並且SELECT使用與使用的相同標準對其進行UPDATE操作非常快。

提前致謝。

聽起來程式碼可能正在使用SAVEPOINTs 來處理錯誤,而不是在繼續之前釋放保存點。這可以解釋大量的虛擬 xid 鎖。

RELEASE SAVEPOINT在你完成一個步驟之後。

您可能還想考慮將工作分批成更小的塊,因為:

  • SAVEPOINT
  • 試試吧
  • ROLLBACK TO SAVEPOINT如果失敗,RELEASE SAVEPOINT如果成功

模式有效,但有一些性能成本會隨著事務中保存點的數量而增加。

這也適用於 PL/PgSQLBEGIN ... EXCEPTION塊。

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