Postgresql
如果其他列被索引,Postgres 更新緩慢?
某些更新在大型 Postgres 表上花費的時間太長。鑑於這些條件:
- 只有一列正在更新,並且它是非索引的
- 由於先前的更新,該列中的每一行都已包含數據
- 數據沒有改變大小(例如,重寫布爾值)
- 此表或任何其他表中沒有其他列依賴於正在更新的列的值
- 沒有對數據庫執行其他查詢(這是工作站上的個人研究數據庫,而不是企業數據庫)
- 其他列上有索引
- 帶有 Bitlocker 的旋轉驅動器(不是 SSD)和帶有 Windows 8.1 x64 的快速 PC
- 該表有 1000 萬行和 60 列
…您會認為,與使用 Bitlocker 旋轉媒體的預期相比,更新將花費合理的時間。我們不會創建更多數據,因此不需要在 HDD 上移動現有數據,只需將其覆蓋即可。其他索引不應該需要更改。等等。相反,經過 20 小時的持續硬碟研磨,我厭倦了等待並停止查詢。如果我刪除其他列上的所有索引並重新執行查詢,則只需大約 30 分鐘。
為什麼與此查詢無關的列上的索引會增加更新時間?
我們不會創建更多數據,因此不需要在 HDD 上移動現有數據,只需將其覆蓋即可
事實並非如此。
為了支持回滾和崩潰安全,PostgreSQL 必須為每個修改的行編寫一個新副本,而不是就地修改行。實際上是兩次,因為它必須先寫入 WAL(用於崩潰恢復的順序日誌),然後再寫入表。
PostgreSQL 的 autovacuum 稍後會出現,並將舊的行版本標記為可以重複使用的可用空間。
有關並發控制和 MVCC 的更多資訊,請參閱使用者手冊。
數據沒有改變大小(例如,重寫布爾值)
無關緊要,因為無論如何都必須重寫該行。
只有一列正在更新,它是非
索引的,其他列上有索引
這只在影響 HOT 更新的情況下很重要,如果沒有修改索引列並且同一磁碟頁面(8k 塊)上有足夠的可用空間來儲存排。
為什麼與此查詢無關的列上的索引會增加更新時間?
在大多數情況下,即使您沒有修改索引列,PostgreSQL 也必須添加新的索引條目,因為它必須將新版本的行寫入單獨的數據庫頁面。
設置 a
FILLFACTOR
of50
或更少可以對此有所幫助,因為它鼓勵 PostgreSQl 保留更多可用空間用於更新,但代價是掃描必須讀取和處理更多數據。