對帶有 GIN 索引的 PostgreSQL 表的偶爾/間歇性、慢速(10 秒以上)UPDATE 查詢
設置
我正在使用 Debian Linux (8) 的基於 SSD 的四核虛擬專用伺服器 (VPS) 上執行 PostgreSQL 9.4.15。相關表有大約 200 萬條記錄。
記錄經常被插入,甚至更頻繁地(不斷地——至少每隔幾秒鐘)更新。據我所知,我已經為這些操作快速執行了所有適當的索引,但是,它們在絕大多數情況下都會立即執行(以毫秒為單位)。
問題
然而,每隔一小時左右,其中一個
UPDATE
查詢就會花費過多的時間——比如 10 秒或更長時間。當這種情況發生時,它通常就像被“阻塞”的“批次”查詢,幾乎同時終止。就好像其中一個查詢或其他一些後台操作(例如,vacuum)正在阻止它們。架構
表 ,
items
有很多列,但我認為以下是唯一可能與問題相關的列:
id INTEGER NOT NULL
(首要的關鍵)search_vector TSVECTOR
last_checkup_at TIMESTAMP WITHOUT TIME ZONE
這些是相關的指標:
items_pkey PRIMARY KEY, btree (id)
items_search_vector_idx gin (search_vector)
items_last_checkup_at_idx btree (last_checkup_at)
可能的罪魁禍首
最後,在我的日誌文件中發出“連接洩漏”警告時,將一個小腳本組合在一起轉儲
pg_stat_activity
(所有活動 Postgres 連接/查詢的列表)的內容後,我縮小了可能的罪魁禍首查詢/列(假設問題不是外部的,例如行為不端的 VPS)。粗略地說,這些查詢似乎一次又一次地出現:
UPDATE items SET last_checkup_at = $1 WHERE items.id = 123245
UPDATE items SET search_vector = [..] WHERE items.id = 78901
這些內容略有解釋,但我真的懷疑缺少任何相關內容。偶爾也會出現其他查詢(在其他表上),但這些查詢通常看起來只是“不幸”被捲入其中。
現在,即使第一個查詢(設置
last_checkup_at
)往往出現大多數時間,設置的查詢search_vector
似乎每次都出現。(此外,通常發出第一個查詢的實例可能更多,這使得它更有可能只是偶然出現。)(我想我在這裡尋找一個解決方案,但即使我把它放在包裡,我也想在這里為其他人記錄這個事件……我已經被這個問題迷惑了幾個月,然後才有機會深潛。)
問題似乎出在 Postgres 的 "
FASTUPDATE
" 機制上。
FASTUPDATE
是索引上可用的設置GIN
,啟用後會導致對索引的更改(由UPDATE
s 引起,並且可能也是由 s 引起的INSERT
)被“排隊”。然後,一旦這個“隊列”變得太大,待處理的條目就會正確地集成到GIN
索引中。的目的
FASTUPDATE
是(毫不奇怪)加快索引更新,但不幸的是,它會導致偶爾UPDATE
的查詢異常緩慢。在我的情況下,我發現最好先進行命中(主要是為了避免在我的日誌中出現“慢查詢”的警告)。
FASTUPDATE
顯然是預設啟用的,並且自 PostgreSQL 8.4 起可用。我能夠像這樣禁用它:ALTER INDEX items_search_vector_idx SET (FASTUPDATE=OFF);
在撰寫本文時,我已經執行了將近一周,幾乎沒有慢查詢。(除了一個我預計需要很長時間的查詢,我幾乎沒有註意到其他問題。)
您還可以在 Postgres 郵件列表的相關主題中找到更多相關資訊。有趣的是,其中一位 Postgres 開發人員(Tom Lane)建議處理
FASTUPDATE
待處理的項目“不應該阻止並發插入”,但我不確定這是否正確;就我而言,我會看到幾個查詢被“備份”,然後一次完成。