Article

PostgreSQLのignore_system_indexesでカタログ索引破損から復旧する仕組み

PostgreSQLの`ignore_system_indexes`は、壊れたシステムカタログ索引を読み取り経路から外し、`REINDEX SYSTEM`へ到達するための復旧用設定です。`-P`の役割、単一ユーザーモードでの流れ、バージョン差、復旧後の検証まで整理します。

Share

こはるの読みどころ

壊れた索引を避けて直すための、かなり限定された復旧スイッチだよ。平常時の設定ではなく、停止・再構築・検証をひと続きで読んでね。

こはるの読みどころ

PostgreSQLのシステムカタログ索引が壊れると、修復コマンドを実行するためのメタデータ参照そのものが失敗することがあります。索引を直したいのに、その索引を使わないと修復を始められない。厄介な循環ですね。

ignore_system_indexesは、この循環を一時的に断つための設定です。Christophe Pettus氏の記事をきっかけに、古くから残る-Pという復旧経路が改めて整理されました。

では、どの場面で有効にし、どこまで信用してよいのでしょうか。平常時のチューニング設定ではなく、隔離したセッションから再構築へ進むための緊急用バイパスとして読み解きます。

壊れたカタログ索引を読まずにREINDEXへ到達する

pg_classpg_attributeなどのシステムカタログには、テーブルや列を扱うためのメタデータが保存されています。通常はカタログ索引が検索を速めますが、その索引自体が破損すると、REINDEXが必要とするカタログ参照まで失敗しかねません。

ignore_system_indexesを有効にしたセッションでは、システムテーブルを読むときにシステム索引を無視します。一方、システムテーブルを書き換えるときの索引更新は続きます。PostgreSQL 18のDeveloper Optionsは、この設定を深刻な損傷からの復旧に使える開発者向けオプションとし、セッション開始後には変更できないと説明しています。

つまり、接続後にSET ignore_system_indexes = onと切り替える設定ではありません。短縮オプションの対応表では、サーバーまたはバックエンド起動時の-Pignore_system_indexes = onに対応します。普段から有効にするものではなく、修復コマンドへたどり着くための入口です。

-Pで起動した単一ユーザーバックエンドからREINDEX SYSTEMへ進む

接続自体が落ちるほどカタログ索引が壊れている場合、PostgreSQL 18のREINDEX文書が示す基本経路は、通常サーバーを停止し、-P付きの単一ユーザーモードで対象データベースを開く方法です。単一ユーザーモードの構文はpostgresコマンドの公式リファレンスで確認できます。

Bash
postgres --single -P -D "/path/to/pgdata" "database_name"

起動後は、対象データベースのシステムカタログ索引をまとめて再構築します。PostgreSQL 18ではデータベース名を省略できます。

SQL
REINDEX SYSTEM;

REINDEX SYSTEMは現在のデータベースにあるシステムカタログ索引を再構築し、共有カタログの索引も対象に含めます。ユーザーテーブルの索引をまとめて直すコマンドではありません。また、システムカタログは並行再構築できないため、REINDEX SYSTEMCONCURRENTLYは使えません。

セッションを通常どおり開始できる場合は、libpq系クライアントからPGOPTIONS-Pを渡す経路も公式文書にあります。

Bash
PGOPTIONS="-P" psql "database_name"

ただし、同じデータベースへほかの利用者が接続したまま修復を進める判断は避けたいところです。公式文書も修復完了までほかの接続を防ぐ選択を勧めています。マネージドPostgreSQLでは単一ユーザーモードやデータディレクトリを利用者が操作できるとは限らないため、提供元の復旧手順、リストア手段、サポート窓口へ切り替えます。

PostgreSQL 14と18ではREINDEX SYSTEMの引数が異なる

この復旧パターンは最近追加された機能ではありません。PostgreSQL 7.1のREINDEX文書は、スタンドアロンのPostgresを-O-Pで起動して破損したシステム索引を直す手順をすでに説明していました。PostgreSQL 8.2のDeveloper Optionsにもignore_system_indexesが載り、読み取りでは索引を無視し、更新時には索引を維持する性質と、セッション開始後に変更できない制約が示されています。

長く残る仕組みでも、コマンド構文はバージョンごとに同じとは限りません。PostgreSQL 14のREINDEX文書ではREINDEX SYSTEMに現在のデータベース名が必須ですが、PostgreSQL 18では省略可能です。

SQL
-- PostgreSQL 14
REINDEX SYSTEM my_database;

-- PostgreSQL 18
REINDEX SYSTEM;

インシデント中に検索結果の最新版だけを見て入力すると、対象クラスタでは構文が合わないことがあります。ランブックには対象メジャーバージョンの公式文書を固定しておくと、ここを切り分けやすくなります。

ignore_system_indexesはすべての索引アクセスを消すスイッチではない

名前からは「システム索引を完全に使わない」と読めますが、用途はもっと狭く考えるべきです。公式仕様が保証する中心は、システムテーブルの読み取りで索引を無視し、書き込み時の索引更新は続けることです。破損状態で不要なDDLを実行すれば、索引への書き込みも発生し得ます。

題材となった記事はさらに、正しい順序が必要な一部の内部処理では警告を出しながら索引を使う場合があることや、-P時にはトリガーやルールの実行順が通常と変わり得ることを実装確認として報告しています。これらは通常運用の互換性を期待できる設定ではない、という判断材料になります。

加えて、カタログ参照が順次走査へ変われば処理は遅くなります。-Pはサービスを劣化運転で継続するためのモードではなく、必要最小限の操作でREINDEX SYSTEMを完了し、通常起動へ戻すためのものだと分かります。

amcheckで再構築を検査し、破損原因まで追う

再起動できたことだけで復旧完了とは言い切れません。PostgreSQL 18のamcheck文書には、bt_index_checkpg_catalog内のB-tree索引を検査する例があり、索引構造の不整合を見つける方法として使えます。

ただし、amcheckは破損の存在を証明できても、不在を証明できないと公式文書は明記しています。さらに、検出した破損に一般的な修復法があるとは限らず、REINDEXだけで直らない場合もあります。

そのため実務上の終点は、索引を再構築することではありません。ログやストレージ、ファイルシステム、メモリ、直前の変更やバックアップ経路を調べ、同じ破損を再発させる原因を切り分けるところまでです。

常設設定ではなく復旧ランブックの最後の逃げ道にする

冒頭の問いへの答えは明確です。ignore_system_indexesは、システムカタログ索引の破損で通常の参照経路が使えないときだけ、REINDEX SYSTEMへ到達するために有効にします。平常時の性能調整や可用性機能ではありません。

備えるなら、-Pという名前だけでは足りません。対象バージョンに合う単一ユーザーモードの起動、接続の隔離、REINDEX SYSTEM、通常起動、amcheck、原因調査を一つのランブックへつなげておく。そうして初めて、この古いスイッチが実際の復旧手段になります。

出典

Share

Related Articles

カテゴリやタグが近い記事を続けて読めるように並べています。