web-dev-qa-db-ja.com

postgresを再インストールした後、保存された古いテーブルスペースにアクセスするにはどうすればよいですか?

したがって、多くのことがここで間違っている可能性があります。私は最初にいくつかのデータを管理するためにhomebrewを介してmac 9.1にpostgres 9.3をインストールしました。私はpostgres.appを使用しています。ハードドライブが小さすぎることが判明したので、テーブルスペースを外部ハードドライブに移行することにしました(これで問題なく動作しました)。次に、基本的にデフォルトのテーブルスペースを変更して、外部ドライブにアクセスしました。次に...数週間後、psqlシェルを実行しようとすると、サブディレクトリにアクセスできず、次のようなエラーが発生しました。

Macbooks-MacBook-Pro:~ macbookpro$ psql
psql: FATAL:  database "macbookpro" does not exist
DETAIL:  The database subdirectory "pg_tblspc/24748/PG_9.3_201306121/16384" is missing.

それで私は周りを見回しても答えが見つからなかったので、postgresを再インストールすることにしました。すべてを再インストールした後、テーブルスペースに再度アクセスしようとしましたが、それはできませんでした!フォルダーには130 GBを超えるデータが含まれているので、そこに何かがあるはずです。

助けてください!データにアクセスするにはどうすればよいですか?

ありがとうございました!

2
Allen Lee

メインデータディレクトリを削除した場合、テーブルスペースの内容に関するすべてのメタデータが失われているため、テーブルスペースのリカバリは困難です。 ( 通常、テーブルスペースを失うと、メインDBを回復できません 。)。

私は本当に、あなたが まともなバックアップ を持っていることを本当に望んでいます。なぜなら、データの回復は困難で時間がかかるからです。 PostgreSQLの内部について多くを学ぶ必要があります。

関係の特定(失われたpg_class

Pgのディスク上のレイアウト は最小限で、システムカタログに格納されているテーブルに関するほとんどすべての情報がpg_classのようなテーブルに格納されています。これは、トランザクションDDLを適切にサポートするために必要です。システムカタログは、メインデータディレクトリの一部です。

各テーブルにメタページがありますが、それだけではわかりません。

テーブルスペースの file layout は、relation-relfileidノードが含まれるデータベース-oidのツリーです。リレーションrelfileidから実際のテーブルへのマッピングは、メインデータベースのpg_classに保存されます。

つまり、ルーズリレーションフォークのコレクションがあり、それらが何であるかを示すメタデータはありません。そしてさらに悪化します。

TOASTテーブル

それでも十分ではなかったかのように、大量のデータは TOASTテーブルにアウトオブラインで保存されます です。

TOASTテーブルをメインテーブルに接続する唯一のものは、システムカタログです。

トランザクションの可視性、失われたpg_clogおよびpg_controldata

PostgreSQLはトランザクションのステータス(進行中のトランザクション、コミットされたトランザクション、ロールバックされたトランザクションなど)をpg_clogに記録します。あなたはそれを推測しました、メインデータベースで。制御ファイルはメインDBにも存在し、トランザクションIDのラップアラウンドポイントなどを追跡します。

テーブル内のすべてのタプルにはxminおよびxmaxフィールドがあり、これらを合わせて、テーブルをスキャンするときにタプルを「見る」必要があるかどうかを読者に伝えます。 xminおよびxmaxの意味でトランザクションIDを示すレコードを失いました。したがって、テーブルを読み取ると、次のようになります。

  • UPDATEが古い行のxmaxをマークし、新しい行を作成した重複行。
  • 削除された行
  • ロールバックされたトランザクションの結果

基本的に、テーブルをまったく読み取ることができる場合、それはダーティーリードになります。

変更が書き込まれず、失われましたpg_xlog

PostgreSQLはpg_xlogへの変更を記録し、lazilyはそれらを(おそらく順不同で)メインリレーションフォークに適用します。クラッシュすると、これらの変更が再生されます。

トランザクションログに問題がなく、バッファキャッシュのメモリ内の状態が良好である限り、ディスク上のステータスが不整合であるかどうかは問題ではありません。

トランザクションログが失われたため、テーブルが部分的にリプレイされた状態になり、データが不整合/無効である可能性があります。

さて、あなたのデータはごちゃごちゃです、とにかくそれから何を回復できますか?

何かを回復する前に、元のデータの完全なコピーを作成します。これを変更しないでください。回復を試みると状況が悪化する可能性があるため、元の状態を維持する必要があります。

また、気になるものを含むPostgreSQLのインストールでは、これを行わないでください。 initdb作業用の使い捨てのPostgreSQLインスタンス。また、同じバージョンのPostgreSQLを正確に使用している必要があります。

最初に行うのは、元のテーブル構造CREATE TABLEです。列を削除したり、列のタイプを変更したりした場合は、テーブルを再作成するときに、正確に何をしたかを繰り返す必要があります。完了したら、テーブルをサポートするrelfilenodeを確認します。

SELECT relname, relfilenode FROM pg_class WHERE relname = 'mytable';

関連するTOASTテーブルのrelfileidも見つける必要があります。

次に、PostgreSQLを切断して完全に停止し(pg_ctl stop -m smart)、失われたテーブルを、新しく再作成されたテーブルのrelfilenodeを含むファイルにコピーします。オリジナルに多数のフォーク(1234.11234.2など)があった場合、それらすべてをコピーして名前を変更する必要があります。ファイルサイズに基づいて、またはstringsを調べることで、どのテーブルが一致するかを突き合わせることができる場合があります。

リレーションに関連付けられているTOASTテーブルについても同じことを行います。

次に スタンドアロンバックエンドモードでPostgreSQLを起動 して、テーブルの読み取りを試みます。

あなたが本当に運が良ければ、クラッシュもERRORもせず、空のテーブルか偽の結果を返すだけです。

この時点で、 pg_dirtyread を使用して、トランザクションの可視性を無視しながらテーブルデータを読み取る必要があります。 the github repo を参照してください。

未加工のPostgreSQLデータベーステーブルをスタンドアロンでダンプするツールがあれば非常に便利ですが、そのようなことはないと思います。

他の人は回復を試みる方法についてより良い提案があるかもしれません。それは私がやったことではなく、今テストする時間もありません。

私はもう少し読んで研究することをお勧めします。誰か他の人がすでにこれについて書いていないか確認してください。さらにアドバイスが必要な場合は、[email protected]にも投稿してください。

1
Craig Ringer