Postgresql

如果其他列被索引,Postgres 更新緩慢?

  • December 11, 2014

某些更新在大型 Postgres 表上花費的時間太長。鑑於這些條件:

  • 只有一列正在更新,並且它是非索引的
  • 由於先前的更新,該列中的每一行都已包含數據
  • 數據沒有改變大小(例如,重寫布爾值)
  • 此表或任何其他表中沒有其他列依賴於正在更新的列的值
  • 沒有對數據庫執行其他查詢(這是工作站上的個人研究數據庫,而不是企業數據庫)
  • 其他列上有索引
  • 帶有 Bitlocker 的旋轉驅動器(不是 SSD)和帶有 Windows 8.1 x64 的快速 PC
  • 該表有 1000 萬行和 60 列

…您會認為,與使用 Bitlocker 旋轉媒體的預期相比,更新將花費合理的時間。我們不會創建更多數據,因此不需要在 HDD 上移動現有數據,只需將其覆蓋即可。其他索引不應該需要更改。等等。相反,經過 20 小時的持續硬碟研磨,我厭倦了等待並停止查詢。如果我刪除其他列上的所有索引並重新執行查詢,則只需大約 30 分鐘。

為什麼與此查詢無關的列上的索引會增加更新時間?

我們不會創建更多數據,因此不需要在 HDD 上移動現有數據,只需將其覆蓋即可

事實並非如此。

為了支持回滾和崩潰安全,PostgreSQL 必須為每個修改的行編寫一個新副本,而不是就地修改行。實際上是兩次,因為它必須先寫入 WAL(用於崩潰恢復的順序日誌),然後再寫入表。

PostgreSQL 的 autovacuum 稍後會出現,並將舊的行版本標記為可以重複使用的可用空間。

有關並發控制和 MVCC 的更多資訊,請參閱使用者手冊。

數據沒有改變大小(例如,重寫布爾值)

無關緊要,因為無論如何都必須重寫該行。

只有一列正在更新,它是非

索引的,其他列上有索引

這只在影響 HOT 更新的情況下很重要,如果沒有修改索引列並且同一磁碟頁面(8k 塊)上有足夠的可用空間來儲存排。

為什麼與此查詢無關的列上的索引會增加更新時間?

在大多數情況下,即使您沒有修改索引列,PostgreSQL 也必須添加新的索引條目,因為它必須將新版本的行寫入單獨的數據庫頁面。

設置 a FILLFACTORof50或更少可以對此有所幫助,因為它鼓勵 PostgreSQl 保留更多可用空間用於更新,但代價是掃描必須讀取和處理更多數據。

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