Postgres 事務下的鎖定問題
我最近收到“共享記憶體不足 - 您可能需要增加 max_locks_per_transaction”錯誤。
這是一個長時間執行的過程,我在正確處理後導入一堆 CSV 文件。我遍歷它們並為每個文件打開一個事務,處理它,然後當我完成文件時,關閉事務並移至下一個文件。
這些文件並不大,最大的大約 12K 行。
就 PG 而言,我所做的處理相當於做幾個
SELECT
s(每行幾個,沒有連接或任何東西),然後是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"
基本上,這些記錄都沒有數據庫或關係,只有事務 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
操作非常快。提前致謝。
聽起來程式碼可能正在使用
SAVEPOINT
s 來處理錯誤,而不是在繼續之前釋放保存點。這可以解釋大量的虛擬 xid 鎖。
RELEASE SAVEPOINT
在你完成一個步驟之後。您可能還想考慮將工作分批成更小的塊,因為:
SAVEPOINT
- 試試吧
ROLLBACK TO SAVEPOINT
如果失敗,RELEASE SAVEPOINT
如果成功模式有效,但有一些性能成本會隨著事務中保存點的數量而增加。
這也適用於 PL/PgSQL
BEGIN ... EXCEPTION
塊。