Postgresql

對帶有 GIN 索引的 PostgreSQL 表的偶爾/間歇性、慢速(10 秒以上)UPDATE 查詢

  • April 5, 2018

設置

我正在使用 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,啟用後會導致對索引的更改(由UPDATEs 引起,並且可能也是由 s 引起的INSERT)被“排隊”。然後,一旦這個“隊列”變得太大,待處理的條目就會正確地集成到GIN索引中。

的目的FASTUPDATE是(毫不奇怪)加快索引更新,但不幸的是,它會導致偶爾 UPDATE的查詢異常緩慢。在我的情況下,我發現最好先進行命中(主要是為了避免在我的日誌中出現“慢查詢”的警告)。

FASTUPDATE顯然是預設啟用的,並且自 PostgreSQL 8.4 起可用。我能夠像這樣禁用它:

ALTER INDEX items_search_vector_idx SET (FASTUPDATE=OFF);

在撰寫本文時,我已經執行了將近一周,幾乎沒有慢查詢。(除了一個我預計需要很長時間的查詢,我幾乎沒有註意到其他問題。)

您還可以在 Postgres 郵件列表的相關主題中找到更多相關資訊。有趣的是,其中一位 Postgres 開發人員(Tom Lane)建議處理FASTUPDATE待處理的項目“不應該阻止並發插入”,但我不確定這是否正確;就我而言,我會看到幾個查詢被“備份”,然後一次完成。

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