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
函式的權限可以授予非超級使用者,但在授予此類權限之前,應仔細考慮資料安全性和隱私方面的問題。儘管這些函式產生的損毀報告並未像對資料結構和發現的損毀性質那樣關注損毀資料的內容,但獲得執行這些函式權限的攻擊者,特別是如果攻擊者還可以誘導損毀,則可能可以從此類訊息中推斷出一些資料本身。
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
陳述式在關係上取得的鎖定模式相同。當 heapallindexed
為 true
時,bt_index_check
不會驗證跨越子/父關係的不變性,但會驗證索引中所有堆積元組是否以索引元組的形式存在。當 checkunique
為 true
時,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
時,此函數會驗證所有應在索引中找到的堆疊元組是否存在。當 checkunique
為 true
時,bt_index_parent_check
將檢查唯一索引中的重複條目中是否只有一個可見。當可選的 rootdescend
參數為 true
時,驗證會透過從根頁面為每個元組執行新的搜尋,重新在葉節點層級尋找元組。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
)。這些鎖可防止來自 INSERT
、UPDATE
和 DELETE
命令的並行資料修改。這些鎖還可防止基礎關係被 VACUUM
以及所有其他公用程式命令並行處理。請注意,此函數僅在執行時持有鎖,而不是在整個交易期間持有鎖。
bt_index_parent_check
的額外驗證更可能偵測到各種異常情況。這些情況可能涉及索引所使用的錯誤實作的 B-Tree 運算子類別,或者假設性的,基礎 B-Tree 索引存取方法程式碼中未發現的錯誤。請注意,與 bt_index_check
不同,當啟用熱備用模式時(即,在唯讀實體複本上),無法使用 bt_index_parent_check
。
bt_index_check
和 bt_index_parent_check
都會以 DEBUG1
和 DEBUG2
嚴重性層級輸出有關驗證過程的日誌訊息。這些訊息提供了有關驗證過程的詳細資訊,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-visible
、all-frozen
和 none
。
預設為 none
。
startblock
如果指定,損毀檢查會從指定的區塊開始,跳過所有先前的區塊。指定超出目標表中區塊範圍的 startblock
是錯誤的。
預設情況下,檢查從第一個區塊開始。
endblock
如果指定,損毀檢查會在指定的區塊結束,跳過所有剩餘的區塊。指定超出目標表中區塊範圍的 endblock
是錯誤的。
預設情況下,會檢查所有區塊。
對於偵測到的每個損毀,verify_heapam
會傳回具有以下欄位的列
blkno
包含損毀頁面的區塊編號。
offnum
損毀元組的 OffsetNumber。
attnum
如果損毀特定於欄,而不是整個元組,則為元組中損毀欄的屬性編號。
msg
描述偵測到的問題的訊息。
heapallindexed
驗證 #當 B-Tree 驗證函數的 heapallindexed
引數為 true
時,會針對與目標索引關係關聯的表執行額外的驗證階段。這包括 「dummy」 CREATE INDEX
作業,該作業會根據暫時性的記憶體中摘要結構檢查所有假設的新索引元組的存在(此結構在基本的第一個驗證階段期間根據需要建置)。摘要結構 「fingerprints」 在目標索引中找到的每個元組。heapallindexed
驗證背後的高階原則是,與現有目標索引等效的新索引只能具有在現有結構中找到的條目。
額外的 heapallindexed
階段會增加大量額外負擔:驗證通常需要更長的時間。但是,執行 heapallindexed
驗證時,取得的關係層級鎖沒有任何變更。
摘要結構的大小受 maintenance_work_mem
的限制。為了確保每個應在索引中表示的堆疊元組偵測到不一致的機率不超過 2%,每個元組大約需要 2 個位元組的記憶體。隨著每個元組可用的記憶體越來越少,遺漏不一致的機率會慢慢增加。此方法顯著限制了驗證的額外負擔,同時僅稍微降低了偵測問題的機率,尤其是對於將驗證視為例行維護工作的安裝。任何單個遺失或格式錯誤的元組都有機會在每次新的驗證嘗試中被偵測到。
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
驗證時,通常有更大的機會檢測到單位元錯誤,因為會測試嚴格的二進位相等性,並且會測試堆積中的索引屬性。
由於錯誤的儲存硬體,或者關係檔案被不相關的軟體覆蓋或修改,可能會發生結構性損壞。 這種損壞也可以使用 資料頁面總和檢查碼 檢測到。
格式正確、內部一致且相對於其自身內部總和檢查碼正確的關係頁面可能仍然包含邏輯損壞。 因此,這種損壞無法使用 總和檢查碼 檢測到。 範例包括主表格中的烤麵包值,這些值缺少烤麵包表格中的對應條目,以及主表格中具有比資料庫或叢集中最舊的有效交易 ID 更舊的交易 ID 的元組。
在生產系統中觀察到多種導致邏輯損壞的原因,包括 PostgreSQL 伺服器軟體中的錯誤、錯誤和構思不周的備份和還原工具,以及使用者錯誤。
損壞的關係在即時生產環境中最令人擔憂,而高風險活動在這些環境中最不受歡迎。 因此,verify_heapam
的設計目的是在沒有不當風險的情況下診斷損壞。 它無法防範後端崩潰的所有原因,因為即使在嚴重損壞的系統上執行呼叫查詢也可能不安全。 執行對 目錄表格 的存取,如果目錄本身已損壞,則可能會出現問題。
通常,amcheck
只能證明存在損壞; 它無法證明其不存在。
任何由 amcheck
引發的關於損壞的錯誤都不應是誤報。 amcheck
在根據定義永遠不應該發生的情況下引發錯誤,因此通常需要仔細分析 amcheck
錯誤。
沒有修復 amcheck
檢測到的問題的一般方法。 應尋找違反不變性的根本原因的解釋。 pageinspect 可能在診斷 amcheck
檢測到的損壞方面發揮有用的作用。 REINDEX
可能無法有效修復損壞。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。