PostgreSQLデータベーステーブルの最終変更日を取得する


35

私は私のテーブルは、それが中に記述されているように、そのファイルの更新日時をチェックすることによって、変更されたときに取得しようとしているこの回答。しかし、結果は常に正しいとは限りません。ファイルの更新日は、テーブルを更新してから数分後に更新されます。それは正しい行動ですか?PostgreSQLはテーブルの変更をキャッシュに保存してからハードドライブにフラッシュしますか?

だから、テーブルの正しい最終変更日を取得するにはどうすればよいですか(自動バキューム変更も大丈夫だと仮定しましょう)?

Linux Centos 6.2 x64でPostgreSQL 9.2を使用しています。


4
ファイルの変更時間は信頼できるとは思わない。また、自動バキュームにより変更される可能性があります。唯一の信頼できる方法は、トリガーによって維持される変更タイムスタンプをテーブルに保存することです。
a_horse_with_no_name

1つのアイデアは、WALファイルに保存された情報が、トランザクションをコミットした後(短いまたは長い)しばらくしてデータファイルに書き込まれることです。必要に応じて、これをキャッシュと呼ぶことができます:)それ以外の場合は、@ a_horse_with_no_nameが言ったことを2番目に言います。
dezso

回答:


35

テーブルの最終変更時刻の信頼できる信頼できる記録はありません。relfilenodeの使用は、多くの理由で間違っています。

  • 書き込みは最初に書き込みヘッドログ(WAL)に記録され、次にヒープ(テーブルファイル)に遅延記録されます。レコードがWALに入ると、Pgはそれを急いでヒープに書き込むことはなく、次のシステムチェックポイントまで書き込まれないこともあります。

  • 大きなテーブルには複数のフォークがあるため、すべてのフォークをチェックして最新のタイムスタンプを選択する必要があります。

  • シンプルSELECTは、ヒントビットの設定により、基になるテーブルへの書き込みアクティビティを生成できます。

  • autovaccumおよびユーザーの表示データを変更しないその他のメンテナンスは、関係ファイルを変更します。

  • のような一部の操作はvaccum full、relfilenodeを置き換えます。適切なロックを取得せずに同時に表示しようとしている場合、期待した場所にならない可能性があります。

いくつかのオプション

信頼性が必要ない場合は、pg_stat_databaseおよびの情報を潜在的に使用できますpg_stat_all_tables。これらは、最後の統計リセットの時間と、最後の統計リセット以降のアクティビティ統計を提供できます。最新のアクティビティがいつであったかはわかりませんが、最後の統計がリセットされてからのことであり、統計がリセットされる前に何が起こったかについての情報はありません。制限されていますが、すでにあります。

確実に行うための1つのオプションは、トリガーを使用して、各テーブルの最終変更時刻を含むテーブルを更新することです。これを行うと、テーブルへのすべての書き込みがシリアル化され、同時実行性失われることに注意してください。また、すべてのトランザクションにかなりのオーバーヘッドが追加されます。お勧めしません。

わずかに少ないひどい代替が使用することですLISTENNOTIFY。外部のデーモンプロセスをPostgreSQLに接続しLISTEN、イベントに接続させます。ON INSERT OR UPDATE OR DELETEトリガーを使用NOTIFYして、テーブルoidを通知ペイロードとして、テーブルが変更されたときにs を送信します。これらは、トランザクションのコミット時に送信されます。デーモンは変更通知を蓄積し、それらをデータベースのテーブルに遅延的に書き戻すことができます。システムがクラッシュした場合、最新の変更の記録は失われますが、大丈夫です。クラッシュ後に起動する場合は、すべてのテーブルを変更されたものとして扱います。

最悪の同時実行性の問題を回避するために、代わりに、before insert or update or delete or truncate on tablename for each statement executeトリガーとしてリレーションoidをパラメーターとして使用するように一般化された変更タイムスタンプを記録できます。これ(relation_oid, timestamp)により、変更ログテーブルにペアが挿入されます。次に、別の接続でヘルパープロセスを使用するか、アプリから定期的に呼び出され、そのテーブルを最新の情報に集約し、最新の変更のサマリーテーブルにマージして、ログテーブルを切り捨てます。listen / notifyアプローチに対するこの唯一の利点は、クラッシュ時に情報を失わないことです-しかし、それはさらに効率的でもありません。

別のアプローチは、テーブルの変更をトラップし、統計情報を遅延更新するためProcessUtility_hookExecutorRun_hook(など)、などを使用するC拡張関数を記述することです。私はこれがどれほど実用的であるかを見ていない。ソースのさまざまな_hookオプションを見てください。

最善の方法は、統計情報コードをパッチしてこの情報を記録し、コアに含めるためにPostgreSQLにパッチを送信することです。コードを書くことから始めないでください。十分に定義された方法が十分にあると考えたら、-hackersでアイデアを上げます(つまり、コードを読むことから始め、「どうやって...」と尋ねるだけではありません)。に最終更新時間を追加するのは良いかもしれませんがpg_stat_...、コミュニティにオーバーヘッドの価値があると納得させるか、オプションで追跡する方法を提供する必要があります -そして、統計を保持するためのコードを記述し、パッチを提出してください。この機能を必要とする人だけがそれを気にするからです。

どうやってやる

これを行う必要があり、それを適切に行うためのパッチを作成する時間がなかった場合、おそらく上で概説したlisten / notifyアプローチを使用するでしょう。

PostgreSQL 9.5コミットタイムスタンプの更新

更新:PostgreSQL 9.5にはコミットタイムスタンプがあります。あなたは彼らがで有効になっている場合はpostgresql.conf(あまりにも過去にそうしました)、あなたは最大で行のコミットのタイムスタンプを確認することができますxminして近似する最終更新時間を。最新の行が削除された場合、それらはカウントされないため、これは近似値にすぎません。

また、コミットタイムスタンプレコードは限られた時間だけ保持されます。そのため、あまり変更されていないテーブルがいつ変更されたかを知りたい場合、答えは事実上「しばらく前」になります。


17

PostgreSQL 9.5では、最後に変更されたコミットを追跡できます。

  1. 次のクエリを使用して、トラックコミットがオンまたはオフであることを確認します

    show track_commit_timestamp;
  2. 「ON」が返された場合は、手順3に進み、それ以外の場合はpostgresql.confを変更します

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf

    変化する

    track_commit_timestamp = off

    track_commit_timestamp = on

    システムを再起動します

    手順1を繰り返します。

  3. 次のクエリを使用して、最後のコミットを追跡します

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;

1
手順2でシステムを再起動する必要はありません。プロセスを再起動するだけです。例えばsudo service postgresql restart
-ijoseph

3

はい、これは予想される動作です-変更に関するデータはトランザクションログにすぐに保存されます。データファイルは、checkpoint_timeout遅延(デフォルトは5分)で更新できます。Postgresは、お客様がリクエストした時間を永久に保持しません。


これがどのように質問に答えているのか理解できません。はい、データをトランザクションログに保存されているが、それは1つが(簡単に、特定のテーブルの更新時刻を得ることができることを意味するものではありません場合は、その内容がログを解析することができ、ログ1のままですが、物事はかなり出て再生されます早く)。
チャールズダフィー

確かに、ログから必要なすべての情報を取得できますが、質問はデータファイルのmtimeに向けられました-データファイルの実現はかなりランダムな場合があります-コミット後数秒-数分(最大1時間)
パベルStehule

OP自身の試みはファイルを見ることでしたが、彼らの本当の意図は明らかにmtimeテーブルを取得することです。しかし、はい、私はあなたがここからどこに来ているのかを理解しています(彼らがやっていたことがうまくいかなかった理由を説明しています)。
チャールズダフィー

2

私が持っているほとんどのクライアントアプリケーションにいくつかのテーブルのキャッシュを維持するために、同じ要件を。ほぼ最後に言ったのは、最後の変更の時刻を本当に知る必要はなく、最後にキャッシュが同期されてから何かが変わったかどうかを検出するだけだからです。

私のアプローチは次のとおりです。

あなたが持って提供id(PK)、 created_on(挿入タイムスタンプ)とupdated_onすることができます(更新タイムスタンプ、NULLかもしれない)各テーブルの列を、

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;

これを連結して行数を追加すると、のようなバージョンタグを作成できます。バージョンタグcount:id#timestampは、テーブル内のデータのすべてのバージョンに対して一意になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.