在只接收 INSERT 的表上執行 VACUUM 是否值得?
在 2015 年的 re:Invent 演講中,AWS 提到,vacuum 不僅應該在更新或刪除之後執行,還應該在插入之後執行。以下是談話的相關部分:
http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s
假設必須對塊進行一些清理,即使它們只接收到插入,並且可以在第一次選擇塊時(減慢讀取速度)或在真空期間進行清理。這是真的嗎?如果是這樣,究竟必須進行哪些清理工作?
tl;dr:送出後讀取數據的第一個程序將設置提示位。這將弄髒頁面,創建寫入活動。另一件事
VACUUM
(但不是其他命令)所做的是將頁面標記為全部可見,如果合適的話。VACUUM
最終將不得不敲桌子來凍結元組。插入後需要完成的工作並不是真正的清理,至少不是其他工作
VACUUM
通常所做的那樣。在詳細介紹之前,請注意此答案基於目前(未發布的)9.6 程式碼,我忽略了流複製的影響,即使它可能會影響可見性。由於MVCC,每次 Postgres 評估元組是否應該對查詢可見時,它必須考慮創建元組的事務(記錄在 xmin 隱藏欄位中)是否已送出,以及其他一些標準。該檢查很昂貴,因此一旦知道所有目前打開的事務都可以看到事務,就會在元組標頭上設置一個“提示位”來指示這一點。該位的設置會弄髒頁面,這意味著必須將其寫入磁碟。如果下一個讀取數據的命令
SELECT
突然產生大量寫入流量,這可能會非常令人困惑。VACUUM
在插入送出之後執行 a將避免這種情況。另一個重要的區別是VACUUM
總是會提示頁面上的元組(只要它在頁面上獲得了清理鎖),但大多數其他命令只會提示插入事務是否在命令開始之前送出。關於編寫所有這些提示位的重要一點是
VACUUM
可以限制(預設情況下自動清空是限制的)。其他命令不會受到限制,並且會盡快生成臟數據。
VACUUM
是將頁面標記為全部可見的唯一方法,這是某些操作(特別是僅索引掃描)的重要性能考慮因素。如果您進行大型插入,很可能有許多頁面只有新插入的元組。VACUUM
可以潛在地將這些頁面標記為全部可見,但前提VACUUM
是啟動時最舊的正在執行的事務比插入數據的事務新。由於 MVCC 的工作方式,插入超過約 20 億次交易的元組必須標記為“凍結”。預設情況下,autovacuum 將在每 2 億筆交易中執行此操作。在批量插入後執行手動真空吸塵器並將vacuum_freeze_min_age 設置為0 有助於減少其影響。更激進的是,您可以
VACUUM FREEZE
在插入後在桌子上執行。這將在下一次凍結掃描發生時“重置時鐘”。如果你想知道具體的細節,請在
HEAPTUPLE_LIVE
呼叫HeapTupleSatisfiesVacuum()
inside後查看案例lazy_scan_heap()
。也可以看看HeapTupleSatisfiesVacuum()
它本身,並將它與HeapTupleSatisfiesMVCC()
.我的另外兩個展示文稿可能很有趣。第一個影片可從http://www.pgcon.org/2015/schedule/events/829.en.html獲得,而第二個影片(我認為更好一點)在https://www.youtube。 com/watch?v=L8nErzxPJjQ