PostgreSQL服務器管理:日常數據庫維護工作
本文檔為PostgreSQL 9.6.0文檔,本轉載已得到原譯者彭煜瑋授權。
PostgreSQL數據庫要求周期性的清理維護。對於很多安裝,讓自動清理守護進程來執行清理已經足夠,如Section 24.1.6所述。你可能需要調整其中描述的自動清理參數來獲得最佳結果。某些數據庫管理員會希望使用手動管理的VACUUM命令來對後台進程的活動進行補充或者替換,這通常使用cron或任務計劃程序腳本來執行。要正確地設置手動管理的清理,最重要的是理解接下來幾小節中討論的問題。依賴自動清理的管理員最好也能略讀該內容以幫助他們理解和調整自動清理。
1.1. 清理的基礎知識
PostgreSQL的VACUUM命令出於幾個原因必須定期處理每一個表:
1.恢複或重用被已更新或已刪除行所占用的磁盤空間。
2.更新被PostgreSQL查詢規劃器使用的數據統計信息。
3.更新可見性映射,它可以加速隻用索引的掃描。
4.保護老舊數據不會由於事務ID回卷或多事務ID回卷而丟失。
正如後續小節中解釋的,每一個原因都將指示以不同的頻率和範圍執行VACUUM操作。
有兩種VACUUM的變體:標準VACUUM和VACUUM FULL。VACUUM FULL可以收回更多磁盤空間但是運行起來更慢。另外,標準形式的VACUUM可以和生產數據庫操作並行運行(SELECT、INSERT、UPDATE和DELETE等命令將繼續正常工作,但在清理期間你無法使用ALTER TABLE等命令來更新表的定義)。VACUUM FULL要求在其工作的表上得到一個排他鎖,因此無法和對此表的其他使用並行。因此,通常管理員應該努力使用標準VACUUM並且避免VACUUM FULL。
VACUUM會產生大量I/O流量,這將導致其他活動會話性能變差。可以調整一些配置參數來後台清理活動造成的性能衝擊
1.2. 恢複磁盤空間
在PostgreSQL中,一次行的UPDATE或DELETE不會立即移除該行的舊版本。這種方法對於從多版本並發控製獲益是必需的:當舊版本仍可能對其他事務可見時,它不能被刪除。但是最後,任何事務都不會再對一個過時的或者被刪除的行版本感興趣。它所占用的空間必須被回收來用於新行,這樣可避免磁盤空間需求的無限製增長。這通過運行VACUUM完成。
VACUUM的標準形式移除表和索引中的死亡行版本並將該空間標記為可在未來重用。不過,它將不會把該空間交還給操作係統,除非在特殊的情況中表尾部的一個或多個頁麵變成完全空閑並且能夠很容易地得到一個排他表鎖。相反,VACUUM FULL通過把死亡空間之外的內容寫成一個完整的新版本表文件來主動緊縮表。這將最小化表的尺寸,但是要花較長的時間。它也需要額外的磁盤空間用於表的新副本,直到操作完成。
例行清理的一般目標是多做標準的VACUUM來避免需要VACUUM FULL。自動清理守護進程嚐試這樣工作,並且實際上永遠不會發出VACUUM FULL。在這種方法中,其思想不是讓表保持它們的最小尺寸,而是保持磁盤空間使用的穩定狀態:每個表占用的空間等於其最小尺寸外加清理之間被用完的空間。盡管VACUUM FULL可被用來把一個表收縮回它的最小尺寸並將該磁盤空間交還給操作係統,但是如果該表將在未來再次增長這樣就沒什麼意義。因此,對於維護頻繁被更新的表,適度運行標準VACUUM運行比少量運行VACUUM FULL要更好。
一些管理員更喜歡自己計劃清理,例如在晚上負載低時做所有的工作。根據一個固定日程來做清理的難點在於,如果一個表有一次預期之外的更新活動尖峰,它可能膨脹得真正需要VACUUM FULL來回收空間。使用自動清理守護進程可以減輕這個問題,因為守護進程會根據更新活動動態規劃清理操作。除非你的負載是完全可以預估的,完全禁用守護進程是不理智的。一種可能的折中方案是設置守護進程的參數,這樣它將隻對異常的大量更新活動做出反應,因而保證事情不會失控,而在負載正常時采用有計劃的VACUUM來做批量工作。
對於那些不使用自動清理的用戶,一種典型的方法是計劃一個數據庫範圍的VACUUM,該操作每天在低使用量時段執行一次,並根據需要輔以在重度更新表上的更頻繁的清理(一些有著極高更新率的安裝會每幾分鍾清理一次它們的最繁忙的表)。如果你在一個集簇中有多個數據庫,別忘記VACUUM每一個,你會用得上vacuumdb程序。
Tip: 當一個表因為大量更新或刪除活動而包含大量死亡行版本時,純粹的VACUUM可能不能令人滿意。如果你有這樣一個表並且你需要回收它占用的過量磁盤空間,你將需要使用VACUUM FULL,或者CLUSTER,或者ALTER TABLE的表重寫變體之一。這些命令重寫該表的一整個新拷貝並且為它構建新索引。所有這些選項都要求排他鎖。注意它們也臨時使用大約等於該表尺寸的額外磁盤空間,因為直到新表和索引完成之前舊表和索引都不能被釋放。
Tip: 如果你有一個表,它的整個內容會被周期性刪除,考慮用TRUNCATE而不是先用DELETE再用VACUUM。TRUNCATE會立刻移除該表的整個內容,而不需要一次後續的VACUUM或VACUUM FULL來回收現在未被使用的磁盤空間。其缺點是會違背嚴格的 MVCC 語義。
1.3. 更新規劃器統計信息
PostgreSQL查詢規劃器依賴於有關表內容的統計信息來為查詢產生好的計劃。這些統計信息由ANALYZE命令收集,它除了直接被調用之外還可以作為VACUUM的一個可選步驟被調用。擁有適度準確的統計信息很重要,否則差的計劃可能降低數據庫性能。
自動清理守護進程如果被啟用,當一個表的內容被改變得足夠多時,它將自動發出ANALYZE命令。不過,管理員可能更喜歡依靠手動的ANALYZE操作,特別是如果知道一個表上的更新活動將不會影響"感興趣的"列的統計信息時。守護進程嚴格地按照一個被插入或更新行數的函數來計劃ANALYZE,它不知道那是否將導致有意義的統計信息改變。
正如用於空間恢複的清理一樣,頻繁更新統計信息對重度更新的表更加有用。但即使對於一個重度更新的表,如果該數據的統計分布沒有很大改變,也沒有必要更新統計信息。一個簡單的經驗法則是考慮表中列的最大和最小值改變了多少。例如,一個包含行被更新時間的timestamp列將在行被增加和更新時有一直增加的最大值;這樣一列將可能需要更頻繁的統計更新,而一個包含一個網站上被訪問頁麵 URL 的列則不需要。URL 列可以經常被更改,但是其值的統計分布的變化相對很慢。
It is possible to run 可以在指定表上運行ANALYZE並且隻在表的指定列上運行,因此如果你的應用需要,可以更加頻繁地更新某些統計。但實際上,通常隻分析整個數據庫是最好的,因為它是一種很快的操作。ANALYZE對一個表的行使用一種統計的隨機采樣,而不是讀取每一個單一行。
Tip: 盡管對每列的ANALYZE頻度調整可能不是非常富有成效,你可能會發現值得為每列調整被ANALYZE收集統計信息的詳細程度。經常在WHERE中被用到的列以及數據分布非常不規則的列可能需要比其他列更細粒度的數據直方圖。見ALTER TABLE SET STATISTICS,或者使用default_statistics_target配置參數改變數據庫範圍的默認值。
還有,默認情況下關於函數的選擇度的可用信息是有限的。但是,如果你創建一個使用函數調用的表達式索引,關於該函數的有用的統計信息將被收集,這些信息能夠大大提高使用該表達式索引的查詢計劃的質量。
Tip: 自動清理守護進程不會為外部表發出ANALYZE命令,因為無法確定一個合適的頻度。如果你的查詢需要外部表的統計信息來正確地進行規劃,比較好的方式是按照一個合適的時間表在那些表上手工運行ANALYZE命令。
1.4. 更新可見性映射
清理機製為每一個表維護著一個可見性映射,它被用來跟蹤哪些頁麵隻包含對所有活動事務(以及所有未來的事務,直到該頁麵被再次修改)可見的元組。這樣做有兩個目的。第一,清理本身可以在下一次運行時跳過這樣的頁麵,因為其中沒有什麼需要被清除。
第二,這允許PostgreSQL回答一些隻用索引的查詢,而不需要引用底層表。因為PostgreSQL的索引不包含元組的可見性信息,一次普通的索引掃描會為每一個匹配的索引項獲取堆元組,用來檢查它是否能被當前事務所見。另一方麵,一次隻用索引的掃描會首先檢查可見性映射。如果它了解到在該頁麵上的所有元組都是可見的,堆獲取就可以被跳過。這對大數據集很有用,因為可見性映射可以防止磁盤訪問。可見性映射比堆小很多,因此即使堆非常大,可見性映射也可以很容易地被緩存起來。
1.5. 防止事務 ID 回卷失敗
PostgreSQL的MVCC事務語義依賴於能夠比較事務 ID(XID)數字:如果一個行版本的插入 XID 大於當前事務的 XID,它就是"屬於未來的"並且不應該對當前事務可見。但是因為事務 ID 的尺寸有限(32位),一個長時間(超過 40 億個事務)運行的集簇會遭受到事務 ID 回卷問題:XID 計數器回卷到 0,並且本來屬於過去的事務突然間就變成了屬於未來 — 這意味著它們的輸出變成不可見。簡而言之,災難性的數據丟失(實際上數據仍然在那裏,但是如果你不能得到它也無濟於事)。為了避免發生這種情況,有必要至少每 20 億個事務就清理每個數據庫中的每個表。
周期性的清理能夠解決該問題的原因是,VACUUM會把行標記為凍結,這表示它們是被一個在足夠遠的過去提交的事務所插入,效果就是該插入事務對所有當前和未來事務來說當然都是可見的。普通 XID 使用模-232算法來比較。這意味著對於每一個普通 XID都有 20 億個 XID "更老"並且有 20 億個"更新",另一種解釋的方法是普通 XID 空間是沒有端點的環。因此,一旦一個行版本創建時被分配了一個特定的普通 XID,該行版本將成為接下來 20 億個事務的"過去"(與我們談論的具體哪個普通 XID 無關)。如果在 20 億個事務之後該行版本仍然存在,它將突然變得好像在未來。要阻止這一切發生,PostgreSQL保留了一個特殊的 XID (FrozenTransactionId),這個 XID 並不遵循普通 XID 的比較規則並且總是被認為比任何普通 XID 要老,被凍結行版本會被看成其插入 XID 為FrozenTransactionId,這樣它們對所有普通事務來說都是"在過去",而不管回卷問題。並且這樣的行版本將一直有效直到被刪除,不管它有多舊。
Note: 在版本 9.4 之前的PostgreSQL中,實際上會通過將一行的插入 XID 替換為FrozenTransactionId來實現凍結,這種 XID 在行的xmin係統列中是可見的。更新的版本僅設置一個標誌位,而保留行中原始的xmin用於可能發生的鑒別用途。不過, 9.4 之前版本的pg_upgrade可能仍會找到xmin等於FrozenTransactionId (2)的行。
此外,係統目錄可能會包含xmin等於BootstrapTransactionId (1)的行,這表示它們是在initdb的第一個階段被插入的。和FrozenTransactionId相似,這個特殊的 XID 被認為比所有正常 XID 的年齡都要老。
vacuum_freeze_min_age控製承載 XID 的行被凍結前該 XID 值應該有多老。如果被凍結的行將很快會被再次修改,增加這個設置可以避免不必要的工作。但是減少這個設置會增加在表必須再次被清理之前能夠流逝的事務數。
VACUUM使用可見性映射來判斷一個表的哪些頁麵必須被掃描。通常,它會跳過不具有任何死亡行版本的頁麵,即便是那些頁麵可能仍然含有具有舊 XID 值的行版本也是如此。因此,通常的VACUUM不會總是凍結表中的每一個舊行版本。VACUUM將偶爾會執行一次激進的清理,這個過程隻會跳過那些既不包含死亡行也不包含任何未凍結 XID 或者 MXID 值的頁麵。vacuum_freeze_table_age控製VACUUM什麼時候會這樣做:如果從上一次這種掃描以來,已經執行的事務數大於vacuum_freeze_table_age 減去vacuum_freeze_min_age則掃描所包含行全部可見但是沒有全部被凍結的頁麵。將vacuum_freeze_table_age設置為 0 會強製VACUUM對所有的掃描都采用這種更激進的策略。
一個表能保持不被清理的最長時間是 20 億個事務減去上次激進清理時的vacuum_freeze_min_age值。如果它超過該時間沒有被清理,可能會導致數據丟失。要保證這不會發生,將在任何包含比autovacuum_freeze_max_age配置參數所指定的年齡更老的 XID 的未凍結行的表上調用自動清理(即使自動清理被禁用也會發生)。
這意味著如果一個表沒有被清理,大約每autovacuum_freeze_max_age減去vacuum_freeze_min_age事務就會在該表上調用一次自動清理。對那些為了空間回收目的而被正常清理的表,這是無關緊要的。然而,對靜態表(包括接收插入但沒有更新或刪除的表)就沒有為空間回收而清理的需要,因此嚐試在非常大的靜態表上強製自動清理的間隔最大化會非常有用。顯然我們可以通過增加autovacuum_freeze_max_age或減少vacuum_freeze_min_age來實現此目的。
vacuum_freeze_table_age的實際最大值是 0.95 * autovacuum_freeze_max_age,高於它的設置將被上限到最大值。一個高於autovacuum_freeze_max_age的值沒有意義,因為不管怎樣在那個點上都會觸發一次防回卷自動清理,並且 0.95 的乘數為在防回卷自動清理發生之前運行一次手動VACUUM留出了一些空間。作為一種經驗法則,vacuum_freeze_table_age應當被設置成一個低於autovacuum_freeze_max_age的值,留出一個足夠的空間讓一次被正常調度的VACUUM或一次被正常刪除和更新活動觸發的自動清理可以在這個窗口中被運行。將它設置得太接近可能導致防回卷自動清理,即使該表最近因為回收空間的目的被清理過,而較低的值將導致更頻繁的激進清理。
增加autovacuum_freeze_max_age(以及和它一起的vacuum_freeze_table_age)的唯一不足是數據庫集簇的pg_clog子目錄將占據更多空間,因為它必須存儲所有向後autovacuum_freeze_max_age範圍內的所有事務的提交狀態。提交時為每個事務使用兩個二進製位,因此如果autovacuum_freeze_max_age被設置為它的最大允許值 20 億,pg_clog將會增長到大約 0.5 吉字節。如果這對於你的總數據庫尺寸是微小的,我們推薦設置autovacuum_freeze_max_age為它的最大允許值。否則,基於你想要允許pg_clog使用的存儲空間大小來設置它(默認情況下 2 億個事務大約等於pg_clog的 50 MB存儲空間)。
減小vacuum_freeze_min_age的一個不足之處是它可能導致VACUUM做無用的工作:如果該行在被替換成FrozenXID之後很快就被修改(導致該行獲得一個新的 XID),那麼凍結一個行版本就是浪費時間。因此該設置應該足夠大,這樣直到行不再可能被修改之前,它們都不會被凍結。
為了跟蹤一個數據庫中最老的未凍結 XID 的年齡,VACUUM在係統表pg_class和pg_database中存儲 XID 的統計信息。特別地,一個表的pg_class行的relfrozenxid列包含被該表的上一次激進VACUUM所用的凍結截止 XID。該表中所有被有比這個截斷 XID 老的普通 XID 的事務插入的行 都確保被凍結。相似地,一個數據庫的pg_database行的datfrozenxid列是出現在該數據庫中的未凍結 XID 的下界 — 它隻是數據庫中每一個表的relfrozenxid值的最小值。一種檢查這些信息的方便方法是執行這樣的查詢:
SELECT c.oid::regclass as table_name,
greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age
FROM pg_class c
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm');
SELECT datname, age(datfrozenxid) FROM pg_database;
age列度量從該截斷 XID 到當前事務 XID 的事務數。
VACUUM通常隻掃描從上一次清理以來被修改過的頁麵,但是隻有當表中每一個可能包含未凍結 XID 的頁麵被掃描時,relfrozenxid才會被推進。當relfrozenxid中的年齡超過vacuum_freeze_table_age個事務時,當使用VACUUM的FREEZE選項時, 或者當所有還沒有被完全凍結的頁麵正好要求清理以移除死亡行版本時,relfrozenxid推進就可能發生。當VACUUM掃描表中每一個還沒有完全凍結的頁麵時,它應該把age(relfrozenxid)設置為一個比所使用的vacuum_freeze_min_age設置大一點的值(差值為從VACUUM開始以來開始的事務數)。如果直到達到autovacuum_freeze_max_age也沒有relfrozenxid推進被VACUUM發出,將會立刻為該表強製執行一次自動清理。
如果出於某種原因自動清理無法從一個表中清除舊的 XID,當數據庫的最舊 XID 和回卷點之間達到 1 千萬個事務時,係統將開始發出這樣的警告消息:
WARNING: database "mydb" must be vacuumed within 177009986 transactions
HINT: To avoid a database shutdown, execute a database-wide VACUUM in "mydb".
(如該示意所建議的,一次手動的VACUUM應該會修複該問題;但是注意該次VACUUM必須由一個超級用戶來執行,否則它將無法處理係統目錄並且因而不能推進數據庫的datfrozenxid)。如果這些警告被忽略,一旦距離回滾點隻剩下 1 百萬個事務時,該係統將會關閉並且拒絕開始任何新的事務:
ERROR: database is not accepting commands to avoid wraparound data loss in database "mydb"
HINT: Stop the postmaster and vacuum that database in single-user mode.
這一百萬個事務的富餘是為了讓管理員能通過手動執行所要求的VACUUM命令進行恢複而不丟失數據。但是,由於一旦係統進入到安全關閉模式,它將不會執行命令。做這個操作的唯一方法是停止服務器並且以單一用戶啟動服務器來執行VACUUM。單一用戶模式中不會強製該關閉模式。
1.5.1. 多事務和回卷
Multixact ID被用來支持被多個事務鎖定的行。由於在一個元組頭部 隻有有限的空間可以用來存儲鎖信息,所以隻要有多於一個事務並發地鎖住一個行, 鎖信息將使用一個"多個事務 ID"(或簡稱多事務 ID)來編碼。任何特定 多事務 ID 中包括的事務 ID 的信息被獨立地存儲在pg_multixact子目 錄中,並且隻有多事務 ID 出現在元組頭部的xmax域中。和事務 ID 類似,多事務 ID 也是用一個 32 位計數器實現,並且也采用了相似的存儲,這些都要 求仔細的年齡管理、存儲清除和回卷處理。在每個多事務中都有一個獨立的存儲區域 保存成員列表,它也使用一個 32 位計數器並且也應被管理。
隻要VACUUM掃描一個表的任何部分,它將會把遇到的任何老於vacuum_multixact_freeze_min_age的多事務 ID 替換成一個不同的值,可能是零值、一個單一事務 ID 或者一個更新的多事務 ID。對於每一個表,pg_class.relminmxid保存仍然出現在該表任一元組中最舊的多事務 ID。如果這個值比vacuum_multixact_freeze_table_age更老,將會強製一次激進的清理。正如上一節所討論的,一次激進的清理意味著隻有那些已知完全凍結的頁麵才會被跳過。可以用pg_class.relminmxid上使用mxid_age()來找到它的年齡。
激進的VACUUM掃描(不管是什麼導致它們)將為表推進該值。最後,當所有數據庫中的所有表被掃描並且它們的最老多事務值被推進,較老的多事務的磁盤存儲可以被移除。
作為一種安全措施,對任何多事務年齡超過autovacuum_multixact_freeze_max_age的表,都將發生一次激進的清理掃描。如果已用的成員存儲空間超過可尋址存儲空間的 50%,基金的清理掃描也將逐步在所有表上進行,這會從那些具有最老多事務年齡的表開始。即使自動清理被在名義上被禁用,這兩中類型的激進掃描都將會發生。
1.6. 自動清理後台進程
PostgreSQL有一個可選的但是被高度推薦的特性autovacuum,它的目的是自動執行VACUUM和ANALYZE 命令。當它被啟用時,自動清理會檢查被大量插入、更新或刪除元組的表。這些檢查會利用統計信息收集功能,因此除非track_counts被設置為true,自動清理不能被使用。在默認配置下,自動清理是被啟用的並且相關配置參數已被正確配置。
"自動清理後台進程"實際上由多個進程組成。有一個稱為自動清理啟動器的常駐後台進程, 它負責為所有數據庫啟動自動清理工作者進程。啟動器將把工作散布在一段時間上,它每隔autovacuum_naptime秒嚐試在每個數據庫中啟動一個工作者(因此,如果安裝中有N個數據庫,則每 autovacuum_naptime/N秒將啟動一個新的工作者)。在同一時間隻允許最多autovacuum_max_workers個工作者進程運行。如果有超過autovacuum_max_workers個數據庫需要被處理,下一個數據庫將在第一個工作者結束後馬上被處理。每一個工作者進程將檢查其數據庫中的每一個表並且在需要時執行VACUUM和/或ANALYZE。可以設置log_autovacuum_min_duration 來監控自動清理工作者進程的活動。
如果在一小段時間內多個大型表都變得可以被清理,所有的自動清理工作者可能都會被占用來在一段長的時間內清理這些表。這將會造成其他的表和數據庫無法被清理,直到一個工作者變得可用。對於一個數據庫中的工作者數量並沒有限製,但是工作者確實會試圖避免重複已經被其他工作者完成的工作。注意運行著的工作者的數量不會被計入max_connections或superuser_reserved_connections限製。
relfrozenxid值比autovacuum_freeze_max_age事務年齡更大的表總是會被清理(這頁表示這些表的凍結最大年齡被通過表的存儲參數修改過,參見後文)。否則,如果從上次VACUUM以來失效的元組數超過"清理閾值",表也會被清理。清理閾值定義為:
清理閾值 = 清理基本閾值 + 清理縮放係數 * 元組數
其中清理基本閾值為autovacuum_vacuum_threshold, 清理縮放係數為autovacuum_vacuum_scale_factor, 元組數為pg_class.reltuples。 失效元組的數量從統計信息收集器獲得,它是一個由每個UPDATE和DELETE命令更新的半準確的計數(它隻是半準確,是因為在高負載的情況下某些信息可能會丟失)。如果表的relfrozenxid值比vacuum_freeze_table_age事務年齡更大,將執行激進的清理以凍結舊元組並增長relfrozenxid,否則隻有從上次清理以來被修改的頁麵會被掃描。
對於分析,也使用了一個相似的閾值:
分析閾值 = 分析基本閾值 + 分析縮放係數 * 元組數
該閾值將與自從上次ANALYZE以來被插入、更新或刪除的元組數進行比較。
臨時表不能被自動清理訪問。因此,臨時表的清理和分析操作必須通過會話期間的SQL命令來執行。
默認的閾值和縮放係數都取自於postgresql.conf, 但是可以為每一個表覆蓋它們(以及很多其他自動清理控製參數), 詳情參見存儲參數。 如果一個設置被通過表的存儲參數修改,那麼在處理該表時使用該值, 否則使用全局設置。
除了基本閾值和縮放係數,還有6個可以通過表的存儲參數設置的自動清理參數。第一個參數是autovacuum_enabled,它可以被設置為false來指示自動清理後台進程整個跳過特定的表。在這種情況中自動清理隻會在需要防止事務ID回卷時清理該表。另外兩個參數是autovacuum_vacuum_cost_delay和autovacuum_vacuum_cost_limit,它們被用來設置表相關的基於代價的清理延遲特性的值。 autovacuum_freeze_min_age、 autovacuum_freeze_max_age和 autovacuum_freeze_table_age被分別用來設置vacuum_freeze_min_age、 autovacuum_freeze_max_age和 vacuum_freeze_table_age的值。
除了基本的閾值和縮放因子之外,還有 6 個自動清理參數可以通過存儲 參數為每個表設置。第一個參數是autovacuum_enabled, 可以被設置為false來指導自動清理守護進程整個跳過 該表。在這種情況下,自動清理隻會在該表必須要清理以便防止事務 ID 回卷時才會動這個表。另外兩個參數 autovacuum_vacuum_cost_delay和 autovacuum_vacuum_cost_limit被用來為基於代價的 清理延遲特性設置與表相關的值。 autovacuum_freeze_min_age、 autovacuum_freeze_max_age和 autovacuum_freeze_table_age分別被用來為 vacuum_freeze_min_age、 autovacuum_freeze_max_age和 vacuum_freeze_table_age設置值。
當多個工作者運行時,在所有運行著的工作者之間代價延遲參數是 "平衡的",這樣不管實際運行的工作者數量是多少, 對於係統的總體 I/O 影響總是相同的。不過,存儲參數 autovacuum_vacuum_cost_delay 或autovacuum_vacuum_cost_limit 被設置的任何正在處理表的工作者不會 被考慮在均衡算法之中。
在某些情況下值得周期性地使用REINDEX命令或一係列獨立重構步驟來重建索引。
已經完全變成空的B樹索引頁麵被收回重用。但是,還是有一種低效的空間利用的可能性:如果一個頁麵上除少量索引鍵之外的全部鍵被刪除,該頁麵仍然被分配。因此,在這種每個範圍中大部分但不是全部鍵最終被刪除的使用模式中,可以看到空間的使用是很差的。對於這樣的使用模式,推薦使用定期重索引。
對於非B樹索引可能的膨脹還沒有很好地定量分析。在使用非B樹索引時定期監控索引的物理尺寸是個好主意。
還有,對於B樹索引,一個新建立的索引比更新了多次的索引訪問起來要略快, 因為在新建立的索引上,邏輯上相鄰的頁麵通常物理上也相鄰(這樣的考慮目前並不適用於非B樹索引)。僅僅為了提高訪問速度也值得定期重索引。
REINDEX在所有情況下都可以安全和容易地使用。但是由於該命令要求一個排他表鎖,因此更好的方法是用一個由創建和替換步驟組成的序列來執行索引重建。支持帶CONCURRENTLY選項的CREATE INDEX的索引類型可以用這種方式重建。如果創建成功並且得到的索引是可用的,則原來的索引可以使用ALTER INDEX和DROP INDEX的命令組合替換成新創建的索引。當一個索引被用於強製唯一性或者其他約束時,可能需要用ALTER TABLE將現有的約束換成由新索引所強製的約束。在使用這種多步重建方法之前應仔細地檢查,因為對於哪些索引可以采用這種方法重索引是有限製的,並且出現的錯誤必須被處理。
把數據庫服務器的日誌輸出保存在一個地方是個好主意, 而不是僅僅通過/dev/null丟棄它們。 在進行問題診斷的時候,日誌輸出是非常寶貴的。不過,日誌輸出可能很龐大(特別是在比較高的調試級別上), 因此你不會希望無休止地保存它們。你需要輪轉日誌文件, 這樣在一段合理的時間後會開始新的日誌文件並且移除舊的。
如果你簡單地把postgres的stderr定向到一個文件中,你會得到日誌輸出, 但是截斷該日誌文件的唯一方法是停止並重起服務器。這樣做對於開發環境中使用的PostgreSQL可能是可接受的,但是你肯定不想在生產環境上這麼幹。
一個更好的辦法是把服務器的stderr輸出發送到某種日誌輪轉程序裏。 我們有一個內建的日誌輪轉程序,你可以通過在 postgresql.conf裏設置配置參數logging_collector為true的辦法啟用它。該程序的控製參數在 Section 19.8.1裏描述。你也可以使用這種方法把日誌數據捕捉成機器可讀的CSV(逗號分隔值)格式。
另外,如果在你已經使用的其他服務器軟件中有一個外部日誌輪轉程序,你可能更喜歡使用它。 比如,包含在Apache發布裏的rotatelogs工具就可以用於PostgreSQL。 要這麼做,隻需要把服務器的stderr用管道重定向到要用的程序。 如果你用pg_ctl啟動服務器,那麼stderr已經重定向到stdout, 因此你隻需要一個管道命令,比如:
pg_ctl start | rotatelogs /var/log/pgsql_log 86400
另外一種生產級的管理日誌輸出的方法就是把它們發送給syslog,讓syslog處理文件輪轉。 要利用這個工具,我們需要設置postgresql.conf裏的log_destination配置參數設置為syslog(記錄syslog日誌)。然後在你想強迫syslog守護進程開始寫入一個新日誌文件的時候, 你就可以發送一個 SIGHUP信號給它。 如果你想自動進行日誌輪轉,可以配置logrotate程序處理 來自syslog的日誌文件。
不過,在很多係統上,syslog不是非常可靠,特別是在麵對大量日誌消息的情況下; 它可能在你最需要那些消息的時候截斷或者丟棄它們。另外,在Linux,syslog會把每個消息刷寫到磁盤上, 這將導致很差的性能(你可以在syslog配置文件裏麵的文件名開頭使用一個"-"來禁用這種行為)。
請注意上麵描述的所有解決方案關注的是在可配置的間隔上開始一個新的日誌文件, 但它們並沒有處理對舊的、不再需要的日誌文件的刪除。你可能還需要設置一個批處理任務來定期地刪除舊日誌文件。 另一種可能的方法是配置日誌輪轉程序,讓它循環地覆蓋舊的日誌文件。
pgBadger是一個外部項目,它可以進行日誌文件的深度分析。 check_postgres可在重要消息出現在日誌文件中時向Nagios提供警告,也可以探測很多其他的特別情況。
最後更新:2017-08-23 14:32:17