★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

F.2. amcheck

amcheckモジュールは、リレーションの構造の論理的な一貫性を検査する機能を提供します。 構造が適正であると見なされれば、エラーは報告されません。

この関数は、特定のリレーションの構造表現における様々な不変量を検査します。 インデックスの走査や、その他の重要な操作を担うアクセスメソッド関数の正しさは、これらの不変量を常に保つことに依存しています。 たとえば、ある関数は、とりわけすべてのB-Treeページの中の項目が論理的な順序になっていることを検査します。(たとえばtextのB-Treeインデックスでは、インデックスタプルは語句の照合順になっていなければなりません。) その特定の不変量が何らかの理由で保たれなければ、該当するページで二分探索が不正なインデックス走査をもたらし、SQL問い合わせに誤った答えを返すことになるでしょう。

検証は、インデックス走査自身で使われるのと同じ手続きを用いて行われます。 その手続きは、ユーザ定義演算子クラスのコードかもしれません。 たとえば、B-Treeインデックスの検査は、一つ以上のB-Treeサポート関数1ルーチンを用いる比較に依存しています。 演算子クラスサポート関数の詳細については37.16.3をご覧ください。

amcheck関数はスーパーユーザだけが使用できます。

F.2.1. 関数

bt_index_check(index regclass, heapallindexed 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の場合には、インデックス中のインデックスタプルに対応するすべてのヒープタプルの存在が検証されます、 実行中のプロダクション環境で定期的、軽量なデータ破損検査が必要な場合、bt_index_checkを使うのが、検査の完全性と、アプリケーションの性能と稼働への影響を限定することとの間の最良のトレードオフになることがしばしばあります。

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

bt_index_parent_checkは、ターゲットとなるB-Treeインデックスが様々な不変量を保っていることを検査します。 オプションとして、heapallindexed引数がtrueの場合、インデックスに対応して存在すべきすべてのヒープタプルの存在を検証します。 省略可能な引数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開発者にとって興味のあるかもしれない検証プロセスに関する詳細な情報を提供します。 検証が実際に非一貫性を検出する追加の状況を提供しますので、上級ユーザにもこの情報は役立つかもしれません。 検証問い合わせを実行する前に対話式のpsqlセッションで

SET client_min_messages = DEBUG1;

を実行すると、扱いやすい程度の詳細で検証の進行状況に関するメッセージを表示します。

F.2.2. オプションheapallindexed検証

検証関数のheapallindexed引数がtrueならば、ターゲットのインデックスリレーションと関連付けられたテーブルに対して追加の検証フェーズが実施されます。 これはダミーCREATE INDEX操作から構成され、インメモリ上の一時的なサマリー構造(これは必要に応じて基礎的な最初の検証フェーズで構築されます)に対する仮想的な新しいインデックスタプルがすべて存在することをチェックします。 サマリー構造はターゲットのインデックスで見つかったすべてのタプルに対して指紋採取(fingerprint)を行います。 heapallindexed検証の背後にある高レベルの原理は、新しいインデックスが既存のインデックスと等しいこと、ターゲットインデックスが既存の構造中に見つかったエントリーのみを含むことです。

追加のheapallindexedフェーズは大きなオーバーヘッドをもたらします。 典型的には、検証に数倍時間かかるようになります。 しかし、取得されたリレーションレベルのロックに対して、heapallindexed検証が実施されるときに変更はありません。

サマライズ構造は、maintenance_work_memによってその大きさが制限されます。 インデックス中に存在すべきヒープタプルの非一貫性の検出失敗の確率が2%を超えないことを保証するために、タプルごとに約2バイトのメモリが必要です。 タプルごとに利用可能なメモリが少ないほど、非一貫性を見逃す可能性が徐々に増えていきます。 この手法によって検証のオーバーヘッドを大幅に減らせる一方、とりわけ検証を日常的な保守作業として行うシステムでは、問題を検出できる確率が少し減少するだけです。 失われた、あるいは不正なタプルは次の検証の機会に検出されます。

F.2.3. amcheckを効果的に使う

amcheckは、データページチェックサムが検知できないような、様々なタイプの障害モードを効果的に検知できます。 以下のようなものがあります。

  • 演算子クラスの正しくない実装によって引き起こされる構造の非一貫性。

    オペレーティングシステムの照合順の比較ルールの変更による問題も含まれます。 textのような照合可能な型のデータの比較は、不変でなけれならず(B-Treeインデックスの走査のための、すべての比較が不変でなければならないのと同じことです)、それはオペレーティングシステムの照合順が決して変化してはいけないことを意味します。 まれであるとは言え、オペレーティングシステムの照合順ルールの更新は、これらの問題を引き起こします。 もっと普通に起こることとしては、マスターサーバとスタンバイサーバの照合順の違いが関与することです。 これは、使用されているオペレーティングシステムのメジャーバージョンに一貫性がないことによります。 そうした一貫性の欠如は一般的にスタンバイサーバでのみ起こるので、通常スタンバイサーバでのみ検出されます。

    そうした問題が起きても、影響を受けた照合順を使って順序付けられた個々のインデックスには影響ないかもしれません。 これは単純に、振る舞いにおける一貫性のなさにかかわらずインデックスされた値は同じ絶対的な順になるからです。 PostgreSQLがオペレーティングシステムのロケールと照合順をどう使用するかについての更なる詳細については、23.123.2をご覧ください。

  • インデックスとインデックス付されたヒープリレーションの間の構造的な非一貫性(heapallindexed検証が実施される場合)

    通常の操作においてはインデックスとそのヒープリレーションの間にはクロスチェックはありません。 ヒープの破壊による症状は些細なものかもしれません。

  • 依拠するPostgreSQLのアクセスメソッド、あるいはソート、トランザクション管理コードにおける、潜在的なまだ見つかっていないバグによる破損。

    新規、あるいは提案中の PostgreSQLの機能が、論理的な非一貫性をもたらしかねないかどうか全般的にテストする際に、インデックスの構造的な一貫性の自動検証が役立ちます。 テーブル構造と、関連する可視性およびトランザクション状態情報の検証も同じような役割を果たします。 わかりやすいテスト戦略の一つは、関数標準の回帰テストを実行中に、amcheckを継続的に呼び出すことです。 テストの実行に関する詳細は、32.1をご覧ください。

  • 単にチェックサムが有効になっていないファイルシステムあるいはストレージサブシステムの障害。

    amcheckは、ブロックをアクセスする際に共有バッファがヒットした場合、検査時に共有メモリバッファ上に表現されたページを調査します。 結果として、amcheckは、検査時にファイルシステムから読み込んだデータを調査するとは限りません。 チェックサムが有効な場合、amcheckは壊れたブロックをバッファに読み込んだ際にチェックサム障害によるエラーを報告するかもしれません。

  • 欠陥のあるRAMあるいは、広範囲に渡るメモリサブシステムによる破損。

    PostgreSQLは、訂正可能なメモリーエラーからは身を守らないので、業界標準のエラー訂正コード(ECC)、あるいはもっと優れた保護機構を使ったRAMを使って運用する前提となっています。 しかし、ECCメモリは典型的には単一ビットエラーに対してのみ耐性があり、メモリ破損に起因する障害に対して完全な保護を提供すると考えるべきではありません。

    heapallindexed検証が実施されると、一般に1ビットエラーを検出する可能性が非常に高くなります。 これは、バイナリ一致を厳密にテストすることと、またヒープ内のインデックス付けされたアトリビュートをテストすることによります。

一般的に、amcheckは破損の存在を証明することはできますが、破損がないことを証明することはできません。

F.2.4. 破損の修復

amcheckが報告するエラーが関与する破損で、偽陽性のものはありません。 amcheckは、定義により発生してはならないはずの条件下で発生したエラーを報告するので、amcheckの報告するエラーを注意深く解析することがしばしば求められます。

amcheckが検出した問題を修復する一般的な方法はありません。 不変条件違反の根本的な原因の説明が求められます。 amcheckが検出した破損の診断には、pageinspectが有用な役割を担うかもしれません。 REINDEXは破損の修復には効果的ではないかもしれません。