PostgreSQL のデータチェックサムが検出するもの、しないもの
PostgreSQL のデータチェックサムは、データページを読むときに破損を検出します。検査が行われるタイミング、pg_checksums でオフラインのまま有効にする方法、pg_stat_database のカウンタ、amcheck とバックアップが受け持つ範囲を整理しました。
ディスクやコントローラ、ファイルシステムは、PostgreSQL が書いたものとは違うバイトを、エラーを出さずに返すことがあります。initdb のドキュメントは、データチェックサムを「そのままでは気づかれない I/O システムによる破損」の検出を助ける機能だと説明しています。この記事では、何が検査されるのか、検査はいつ行われるのか、既存のクラスタでチェックサムを有効にする方法、失敗がどこに記録されるのか、そしてチェックサムが守らないものを順に見ていきます。
基準にしたのは、2026年10月18日時点で最新の安定版である PostgreSQL 18(マイナーリリース 18.6)のドキュメントです。PostgreSQL 19 は2026年10月15日に RC 1 が発表された段階なので、この記事では扱いません。
チェックサムの対象
テーブルとインデックスは固定サイズのページに格納されます(ページの構造は HOT 更新の記事 で扱いました)。ページヘッダの2番目のフィールド pd_checksum は2バイトで、チェックサムが有効ならここにページのチェックサムが入ります。ドキュメントによれば、チェックサムはページを書くときに更新され、ページを読むたびに検証されます。
対象はデータページだけです。内部データ構造と一時ファイルは保護されないと、ドキュメントにはっきり書かれています。
pg_xact、pg_subtrans、pg_multixact、pg_serial、pg_notify、pg_stat、pg_snapshotsは直接にはチェックサムされません。これらが永続的な構造である場合は、クラッシュリカバリ時に最近の変更を正確に再構築できるよう WAL レコードが書かれ、その WAL レコードの側が保護されます。- 大きなクエリがソート、マテリアライズ、中間結果に使う一時ファイルはチェックサムされず、その変更の WAL も書かれません。
WAL には別の保護があります。WAL の各レコードには CRC-32C が付いていて、レコードを書くときに値が設定され、クラッシュリカバリ、アーカイブリカバリ、レプリケーションのときに検査されます。WAL に記録されたフルページイメージは、データチェックサムの設定に関係なく常にチェックサムで保護されます。
チェックサムはクラスタ単位の設定です。特定のデータベースやテーブルだけで有効にすることはできません。
有効かどうかを確かめる
SHOW data_checksums;
data_checksums は、クラスタでチェックサムが有効かどうかを示す読み取り専用のパラメータです。
デフォルトは、クラスタを作ったバージョンによって変わります。PostgreSQL 18 から initdb はデフォルトでチェックサムを有効にし、新しく加わった --no-data-checksums オプションで無効にできます。18 のリリースノートがこれをデフォルトの変更として書いているので、以前のバージョンの initdb で -k を付けずに作ったクラスタはチェックサムが無効になっている可能性があります。同じリリースノートには、pg_upgrade は新旧クラスタのチェックサム設定が一致していることを求めるとも書かれています。チェックサムのないクラスタを 18 に上げるには、新しいクラスタを --no-data-checksums で作るか、後で説明する pg_checksums で旧クラスタのチェックサムを先に有効にする必要があります。
コストについて、initdb のドキュメントはチェックサムを有効にすると「わずかな性能低下があるかもしれない」と書くだけで、数値は示していません。自分で測れるコストの一つは WAL の量です。チェックサムが有効だと、ヒントビットの更新は常に WAL に記録され、wal_log_hints の設定は無視されます。ドキュメントによれば、チェックサムのないクラスタで wal_log_hints を有効にすると、チェックサムを有効にした場合に WAL の記録がどれだけ増えるかを試せます。wal_log_hints はサーバ起動時にしか設定できません。
検査が行われるタイミング
検証は読み取りのときに行われます。ignore_checksum_failure のドキュメントによると、読み取り中にチェックサムの失敗を検出すると、PostgreSQL は通常エラーを報告して現在のトランザクションを中断します。
ここから、ドキュメントが直接は書いていない推論が一つ出てきます。一度も読まれないページは検査もされない、ということです。めったに参照しない古いパーティションが壊れていても、誰かが読むまでは表に出ないかもしれません。普段のワークロードの読み取りより広くチェックサムを検証するツールが二つあります。一つはオンライン、もう一つはオフラインで使います。
pg_basebackup(オンライン):元のサーバでチェックサムが有効なら、ベースバックアップを取る間にデフォルトでチェックサムを検証するので、検査の範囲はバックアップが転送するデータです。失敗すると終了ステータスは0以外になりますが、--no-cleanを指定したときと同じくバックアップは削除されません。失敗はpg_stat_databaseにも記録されます。--no-verify-checksumsでこの検証を無効にできます。pg_checksums --check(オフライン):ドキュメントによれば、クラスタ内のすべてのファイルを走査します。サーバをクリーンに停止した後でないと実行できません。チェックサムエラーがなければ終了ステータスは0、一つでも失敗があれば0以外です。
チェックサムは破損を検出するものです。ページを修復するという説明はドキュメントのどこにもないので、復旧にはバックアップなど別のコピーが必要になります。
既存のクラスタでチェックサムを有効にする
PostgreSQL 18 で initdb の後にチェックサムを有効または無効にする方法は pg_checksums だけで、サーバが停止している必要があります。次のコマンドは説明のための例です。この記事のために実行したものではなく、パスは仮のものです。
# サーバをクリーンに停止した後で
pg_checksums --enable --progress -D /path/to/data
実行前に知っておきたい点です。
- サーバがクリーンに停止している必要があります。
- 有効にするときは、チェックサムが変わるすべてのリレーションファイルのブロックをその場で書き直すため、大きなクラスタでは長い時間がかかることがあります。その間にサーバや、データディレクトリに書き込む他のプログラムを起動してはいけません。起動するとデータが失われるおそれがあります。
- 無効にするとき(
--disable)はpg_controlファイルを更新するだけです。 --no-syncはファイルがディスクに書かれるのを待たずに戻るので、その後に OS がクラッシュするとデータディレクトリが壊れることがあります。ドキュメントはテスト向けで、本番環境では使うべきでないとしています。- 有効化や無効化の途中で
pg_checksumsが中断されたり強制終了されたりしても、クラスタのチェックサム設定は元のまま残り、同じ操作をもう一度実行できます。
レプリケーション構成では別の注意が必要です。pg_rewind のようにリレーションファイルのブロックをノード間で直接コピーするツールを使っていて、ノードごとにチェックサムの設定が揃っていないと、チェックサムの合わないページができることがあります。ドキュメントは、すべてのクラスタを停止してから一斉に同じように切り替えることを勧めています。スタンバイをすべて破棄し、プライマリで操作してからスタンバイを一から作り直す方法も安全だとしています。
何も変えずに検査だけしたい場合は、デフォルトのモードである --check を使います。こちらもクリーンな停止が必要です。
pg_checksums --check --progress -D /path/to/data
失敗が記録される場所
稼働中のサーバが検出したチェックサムの失敗と、pg_basebackup が見つけた失敗は、pg_stat_database ビューに記録されます。
SELECT coalesce(datname, '(shared objects)') AS db,
checksum_failures,
checksum_last_failure
FROM pg_stat_database
WHERE checksum_failures > 0;
checksum_failures:そのデータベース(または共有オブジェクト)で検出されたデータページのチェックサム失敗の数checksum_last_failure:最後に失敗を検出した時刻- チェックサムが無効なら、どちらも NULL です。すべての行でこの列が NULL なら、チェックサムが無効なクラスタです。
- このビューにはデータベースごとに1行と、共有オブジェクト用の1行があります。その行は
datidが0でdatnameが NULL なので、上のクエリではcoalesceを使っています。
checksum_failures が増えたら通知が飛ぶようにしておけば、アプリケーションログのエラーに誰かが気づくのを待たずに済みます。これはドキュメントが定めた手順ではなく、提案です。オフラインの pg_checksums --check の結果は、このビューで探さないでください。このツールはサーバを停止した状態で実行され、ドキュメントは結果をコマンドの出力と終了ステータス(一つでも失敗があれば0以外)でしか説明しておらず、pg_stat_database には触れていません。
破損の後に使う設定
ドキュメントは、ページの破損から復旧するときの設定を二つ挙げています。どちらもデフォルトは off で、スーパーユーザか適切な SET 権限を持つユーザしか変更できません。
ignore_checksum_failure は、チェックサムが有効なときにだけ効果があります。エラーを警告に変えて処理を続けるので、ブロックヘッダが正常なら、壊れていない行を取り出せるかもしれません。ヘッダそのものが壊れていれば、この設定を有効にしていてもエラーになります。ドキュメントは、この設定がクラッシュを引き起こしたり、破損を広げたり隠したり、他の深刻な問題につながったりするおそれがあると警告しています。
zero_damaged_pages は、壊れたページヘッダを検出したときに、そのページをメモリ上でゼロで埋めて処理を続けます。そのページにあった行はすべて失われます。ドキュメントは、壊れたページからデータを取り戻すことを諦めるまでは有効にしないよう求めています。ゼロで埋めたページはディスクに強制的には書かれないので、設定を off に戻す前にそのテーブルやインデックスを作り直すことを勧めています。
どちらも破損が起きた後にデータを取り出すための設定で、普段から有効にしておくものではありません。
チェックサムでは代わりにならないもの
ページの形式が正しく、内部的に整合していて、自分のチェックサムとも一致しているのに、中身が論理的に間違っていることがあります。amcheck のドキュメントは二つの例を挙げています。TOAST テーブルに対応するエントリがない本体テーブルの TOAST 値と、最も古い有効なトランザクション ID よりも古いトランザクション ID を持つタプルです。同じドキュメントは、チェックサムでは検出できず amcheck なら検出できる障害も挙げています。
- 誤った演算子クラスの実装による構造の不整合
- インデックスとテーブルの不整合(
heapallindexedの検証を行う場合) - PostgreSQL のアクセスメソッド、ソート、トランザクション管理のコードにあるかもしれない未発見のバグによる破損
- 不良な RAM やメモリサブシステムによる破損
メモリについては、信頼性の章に、PostgreSQL は訂正可能なメモリエラーを防がず、ECC 以上の RAM を使うことを前提にしていると書かれています。チェックサムはページを書くときに計算されるので、その時点でメモリ上のバイトがすでに間違っていれば、チェックサムも間違ったバイトに対して計算されます。
まとめると、チェックサムはストレージとの行き来の間にバイトが変わったことに気づくためのものです。リレーション内やリレーション間の論理的な整合性は amcheck(verify_heapam、bt_index_check、bt_index_parent_check、gin_index_check)が、破損した後のデータの復旧はバックアップが受け持ちます。プログラムがファイルに書くときに OS が何を約束するのかは、write() と fsync の記事 で扱いました。
参考にしたドキュメント
- PostgreSQL 18 — 28.2 Data Checksums:対象範囲、検査のタイミング、オフラインでの有効化
- PostgreSQL 18 — pg_checksums:モード、終了ステータス、レプリケーションと中断の注意
- PostgreSQL 18 — initdb:
--data-checksums、--no-data-checksums - PostgreSQL 18 — Release Notes:デフォルトの変更、
pg_upgradeの条件 - PostgreSQL 18 — 28.1 Reliability:WAL の CRC、チェックサムの対象外、ECC
- PostgreSQL 18 — 66.6 Database Page Layout:
pd_checksum - PostgreSQL 18 — 19.5 Write Ahead Log:
wal_log_hints - PostgreSQL 18 — 19.15 Preset Options:
data_checksums - PostgreSQL 18 — 19.17 Developer Options:
ignore_checksum_failure、zero_damaged_pages - PostgreSQL 18 — 27.2 The Cumulative Statistics System:
pg_stat_database - PostgreSQL 18 — pg_basebackup:
--no-verify-checksums - PostgreSQL 18 — F.1 amcheck:チェックサムでは検出できない破損
- PostgreSQL Versioning Policy:現在のマイナーリリース
リンクと内容は2026年10月18日に確認しました。