支援版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援版本:12 / 11 / 10

F.1. amcheck — 用於驗證表和索引一致性的工具 #

amcheck 模組提供了讓您驗證關係結構之邏輯一致性的函數。

B-Tree 檢查函數會驗證特定關係表示結構中的各種不變量。索引掃描和其他重要操作背後的存取方法函數的正確性依賴於這些不變量始終成立。例如,某些函數會驗證,除此之外,所有 B-Tree 頁面中的項目都以邏輯順序排列(例如,對於 text 上的 B-Tree 索引,索引元組應按排序後的詞彙順序排列)。如果該特定不變量以某種方式未能成立,我們可以預期在受影響頁面上的二進位搜尋會不正確地引導索引掃描,導致 SQL 查詢的錯誤答案。如果結構看起來有效,則不會引發錯誤。在執行這些檢查函數時,search_path 會暫時變更為 pg_catalog, pg_temp

驗證使用與索引掃描本身使用的相同程序來執行,索引掃描本身可能是使用者定義的運算子類別程式碼。例如,B-Tree 索引驗證依賴於使用一個或多個 B-Tree 支援函數 1 常式進行的比較。有關運算子類別支援函數的詳細資訊,請參閱第 36.16.3 節

與透過引發錯誤來報告損壞的 B-Tree 檢查函數不同,堆疊檢查函數 verify_heapam 會檢查一個表,並嘗試傳回一組列,每個損壞都有一列。儘管如此,如果 verify_heapam 依賴的設施本身已損壞,則該函數可能無法繼續,而是可能會引發錯誤。

執行 amcheck 函數的許可權可以授予非超級使用者,但在授予此類許可權之前,應仔細考慮資料安全和隱私問題。儘管這些函數產生的損壞報告並未如此著重於已損壞資料的內容,而是著重於該資料的結構和找到的損壞性質,但獲得執行這些函數許可權的攻擊者,特別是如果攻擊者還可以誘導損壞,可能能夠從此類訊息中推斷出資料本身的一些資訊。

F.1.1. 函數 #

bt_index_check(index regclass, heapallindexed boolean, checkunique boolean) returns void

bt_index_check 測試其目標(B-Tree 索引)是否符合各種不變量。範例用法

test=# SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique),
               c.relname,
               c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog'
-- Don't check temp tables, which may be from another session:
AND c.relpersistence != 't'
-- Function may throw an error when this is omitted:
AND c.relkind = 'i' AND i.indisready AND i.indisvalid
ORDER BY c.relpages DESC LIMIT 10;
 bt_index_check |             relname             | relpages
----------------+---------------------------------+----------
                | pg_depend_reference_index       |       43
                | pg_depend_depender_index        |       40
                | pg_proc_proname_args_nsp_index  |       31
                | pg_description_o_c_o_index      |       21
                | pg_attribute_relid_attnam_index |       14
                | pg_proc_oid_index               |       10
                | pg_attribute_relid_attnum_index |        9
                | pg_amproc_fam_proc_index        |        5
                | pg_amop_opr_fam_index           |        5
                | pg_amop_fam_strat_index         |        5
(10 rows)

此範例顯示了一個工作階段,該工作階段對資料庫test中 10 個最大的目錄索引執行驗證。針對唯一索引的子集要求驗證索引元組中堆疊元組的存在。由於未引發錯誤,因此所有測試的索引似乎在邏輯上是一致的。當然,可以輕鬆變更此查詢,以便為資料庫中支援驗證的每個索引呼叫 bt_index_check

bt_index_check 在目標索引及其所屬的堆疊關係上取得 AccessShareLock。此鎖定模式與簡單 SELECT 陳述式在關係上取得的鎖定模式相同。bt_index_check 不會驗證跨越子/父關係的不變量,但當 heapallindexedtrue 時,將驗證索引中所有堆疊元組的存在。當 checkuniquetrue 時,bt_index_check 將檢查在唯一索引中的重複項目中,是否不多於一個項目可見。當需要對線上生產環境中的損壞進行常式、輕量級測試時,使用 bt_index_check 通常可以在驗證的徹底性和限制對應用程式效能和可用性的影響之間提供最佳權衡。

bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean, checkunique boolean) returns void

bt_index_parent_check 測試目標 B-Tree 索引是否符合各種不變性。選擇性地,當 heapallindexed 參數為 true 時,此函數會驗證索引中是否包含所有應該存在的堆疊元組。當 checkuniquetrue 時,bt_index_parent_check 將檢查唯一索引中的重複條目中是否只有一個是可見的。當選擇性參數 rootdescendtrue 時,驗證會透過從根頁面為每個元組執行新的搜尋,在葉節點層級重新尋找元組。bt_index_parent_check 可以執行的檢查是 bt_index_check 可以執行的檢查的超集合。bt_index_parent_check 可以被認為是 bt_index_check 更徹底的變體:與 bt_index_check 不同,bt_index_parent_check 也會檢查跨越父/子關係的不變性,包括檢查索引結構中是否有遺失的下行鏈結。bt_index_parent_check 遵循一般慣例,如果發現邏輯不一致或其他問題,則會引發錯誤。

bt_index_parent_check 需要目標索引上的 ShareLock (也會在堆疊關係上取得 ShareLock)。這些鎖可防止來自 INSERTUPDATEDELETE 命令的並行資料修改。這些鎖也防止底層關係被 VACUUM 以及所有其他公用程式命令並行處理。請注意,該函數僅在執行時持有鎖,而不是在整個交易期間持有鎖。

bt_index_parent_check 的額外驗證更可能檢測到各種病態情況。這些情況可能涉及由所檢查的索引使用的錯誤實作的 B-Tree 運算子類別,或者,假設在底層 B-Tree 索引存取方法程式碼中存在尚未發現的錯誤。請注意,與 bt_index_check 不同,當啟用熱備用模式 (即,在唯讀實體副本上) 時,無法使用 bt_index_parent_check

提示

bt_index_checkbt_index_parent_check 都會以 DEBUG1DEBUG2 嚴重性層級輸出關於驗證過程的日誌訊息。這些訊息提供關於驗證過程的詳細資訊,PostgreSQL 開發人員可能會感興趣。進階使用者也可能會發現此資訊很有幫助,因為如果驗證實際上檢測到不一致,它可以提供額外的上下文。執行

SET client_min_messages = DEBUG1;

在互動式 psql 會話中,在執行驗證查詢之前,會以可管理的詳細程度顯示關於驗證進度的訊息。

verify_heapam(relation regclass, on_error_stop boolean, check_toast boolean, skip text, startblock bigint, endblock bigint, blkno OUT bigint, offnum OUT integer, attnum OUT integer, msg OUT text) returns setof record

檢查表格、序列或具體化檢視是否存在結構性損毀,其中關係中的頁面包含格式無效的資料,以及邏輯性損毀,其中頁面在結構上有效,但與資料庫叢集的其餘部分不一致。

識別以下可選引數

on_error_stop

如果為 true,則損毀檢查會在找到任何損毀的第一個區塊的末尾停止。

預設為 false。

check_toast

如果為 true,則會針對目標關係的 TOAST 表格檢查 toasted 值。

已知此選項速度很慢。此外,如果 toast 表格或其索引已損毀,則針對 toast 值檢查可能會導致伺服器崩潰,儘管在許多情況下只會產生錯誤。

預設為 false。

skip

如果不是 none,則損毀檢查會跳過標記為 all-visible 或 all-frozen 的區塊,如指定。有效的選項為 all-visibleall-frozennone

預設為 none

startblock

如果指定,則損毀檢查會從指定的區塊開始,跳過所有先前的區塊。指定超出目標表格中區塊範圍的 startblock 是一個錯誤。

預設情況下,檢查從第一個區塊開始。

endblock

如果指定,則損毀檢查會在指定的區塊結束,跳過所有剩餘的區塊。指定超出目標表格中區塊範圍的 endblock 是一個錯誤。

預設情況下,會檢查所有區塊。

對於檢測到的每個損毀,verify_heapam 會傳回具有以下欄位的列

blkno

包含損毀頁面的區塊編號。

offnum

損毀元組的 OffsetNumber。

attnum

元組中損毀欄位的屬性編號,如果損毀是特定於欄位而不是整個元組。

msg

描述檢測到的問題的訊息。

F.1.2. 選擇性 heapallindexed 驗證 #

當 B-Tree 驗證函數的 heapallindexed 引數為 true 時,會針對與目標索引關係關聯的表格執行額外的驗證階段。這包括 虛擬 CREATE INDEX 作業,該作業會針對暫時性的記憶體摘要結構檢查所有假設的新索引元組是否存在 (這會在驗證的基本第一階段期間根據需要建置)。摘要結構會 指紋辨識 目標索引中找到的每個元組。heapallindexed 驗證背後的高層次原則是,與現有目標索引等效的新索引必須只有可以在現有結構中找到的項目。

額外的 heapallindexed 階段會增加顯著的負擔:驗證通常會花費幾倍的時間。但是,執行 heapallindexed 驗證時,取得的關係層級鎖沒有變化。

摘要結構的大小受 maintenance_work_mem 限制。為了確保每個應在索引中表示的堆疊元組檢測到不一致的機率不超過 2%,每個元組大約需要 2 個位元組的記憶體。隨著每個元組可用的記憶體減少,遺漏不一致的機率會緩慢增加。這種方法顯著限制了驗證的負擔,同時僅稍微降低了檢測到問題的機率,尤其是對於將驗證視為例行維護任務的安裝。任何單個缺失或格式錯誤的元組都有機會在每次新的驗證嘗試中被檢測到。

F.1.3. 有效地使用 amcheck #

amcheck 可以有效地檢測各種 資料總和檢查碼 無法捕捉到的故障模式。這些包括

  • 由不正確的運算子類別實作造成的結構性不一致。

    這包括因作業系統校對規則變更而引起的問題。諸如 text 等具有校對規則類型之資料的比對必須是不可變的(就像用於 B-Tree 索引掃描的所有比對必須是不可變的一樣),這意味著作業系統校對規則絕不能更改。雖然很少見,但作業系統校對規則的更新可能會導致這些問題。更常見的是,主伺服器和備用伺服器之間的校對順序不一致,這可能是因為使用的作業系統主要版本不一致。這種不一致通常只會在備用伺服器上出現,因此通常只能在備用伺服器上檢測到。

    如果出現此類問題,它可能不會影響使用受影響校對規則排序的每個單獨索引,僅僅是因為索引值可能恰好具有相同的絕對排序,而與行為不一致無關。有關 PostgreSQL 如何使用作業系統地區設定和校對規則的更多詳細資訊,請參閱第 23.1 節第 23.2 節

  • 索引與被索引的堆積關聯之間的結構不一致(當執行 heapallindexed 驗證時)。

    在正常操作期間,不會對索引與其堆積關聯進行交叉檢查。堆積損壞的徵兆可能難以察覺。

  • 由底層 PostgreSQL 存取方法程式碼、排序程式碼或事務管理程式碼中假設存在的未發現錯誤引起的損壞。

    索引結構完整性的自動驗證在新或擬議的 PostgreSQL 功能的一般測試中發揮作用,這些功能可能會引入邏輯不一致。表結構以及相關的可見性和事務狀態資訊的驗證也起著類似的作用。一種顯然的測試策略是在執行標準迴歸測試時連續呼叫 amcheck 函式。有關執行測試的詳細資訊,請參閱第 31.1 節

  • 檔案系統或儲存子系統故障,其中恰好未啟用總和檢查碼。

    請注意,如果存取區塊時只有共享緩衝區命中,則 amcheck 會檢查驗證時共享記憶體緩衝區中表示的頁面。因此,amcheck 不一定會檢查驗證時從檔案系統讀取的資料。請注意,啟用總和檢查碼後,當將損壞的區塊讀取到緩衝區時,amcheck 可能會因總和檢查碼失敗而引發錯誤。

  • 由有缺陷的 RAM 或更廣泛的記憶體子系統引起的損壞。

    PostgreSQL 不會防止可糾正的記憶體錯誤,並且假設您將使用採用業界標準錯誤校正碼 (ECC) 或更好保護的 RAM 進行操作。但是,ECC 記憶體通常僅能抵禦單一位元錯誤,不應假定它能提供針對導致記憶體損壞的故障的絕對保護。

    當執行 heapallindexed 驗證時,通常會有更大的機率檢測到單一位元錯誤,因為會測試嚴格的二進位相等性,並且會測試堆積中的索引屬性。

結構性損壞可能是由於有缺陷的儲存硬體或關聯檔案被不相關的軟體覆寫或修改而發生的。這種損壞也可以使用資料頁總和檢查碼來檢測。

格式正確、內部一致且相對於其自身內部總和檢查碼正確的關聯頁面可能仍然包含邏輯損壞。因此,這種損壞無法使用 總和檢查碼 檢測。範例包括主表中的 toasted 值,這些值缺少 toast 表中的相應條目,以及主表中的元組,其事務 ID 早於資料庫或叢集中最早的有效事務 ID。

在生產系統中觀察到多種邏輯損壞的原因,包括 PostgreSQL 伺服器軟體中的錯誤、有缺陷且設計不佳的備份和還原工具以及使用者錯誤。

損壞的關聯在即時生產環境中最令人擔憂,而高風險活動在這些環境中最不受歡迎。因此,verify_heapam 旨在診斷損壞而不會造成不必要的風險。它不能防止後端崩潰的所有原因,因為即使執行呼叫查詢在嚴重損壞的系統上也是不安全的。執行對目錄表的存取,如果目錄本身已損壞,則可能會出現問題。

一般來說,amcheck 只能證明存在損壞;它無法證明不存在損壞。

F.1.4. 修復損壞 #

amcheck 引發的有關損壞的任何錯誤都不應是假陽性。amcheck 在根據定義永遠不應發生的情況下引發錯誤,因此通常需要仔細分析 amcheck 錯誤。

沒有通用的方法來修復 amcheck 檢測到的問題。應尋找違反不變性的根本原因的解釋。pageinspect 可能在診斷 amcheck 檢測到的損壞方面發揮有用的作用。REINDEX 可能無法有效地修復損壞。

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表格報告文件問題。