sql >> データベース >  >> RDS >> PostgreSQL

マテリアライズド・ビューが常に最新であることを確認するにはどうすればよいですか?

    REFRESH MATERIALIZED VIEWを呼び出す必要があります 関係するテーブルを変更するたびに、そうですか?

    はい、PostgreSQL自体が自動的に呼び出すことはありません。何らかの方法で呼び出す必要があります。

    これを行うにはどうすればよいですか?

    これを達成するための多くの方法。いくつかの例を示す前に、 REFRESH MATERIALIZED VIEWに注意してください。 コマンドはAccessExclusiveモードでビューをブロックするため、機能している間は SELECTを実行することもできません。 テーブルの上。

    ただし、バージョン9.4以降を使用している場合は、 CONCURRENTLYを指定できます。 オプション:

    REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
    

    これによりExclusiveLockが取得され、 SELECTはブロックされません。 クエリを実行しますが、オーバーヘッドが大きくなる可能性があります(変更されたデータの量によって異なりますが、変更された行が少ない場合は、より高速になる可能性があります)。それでも2つのREFRESHを実行することはできませんが コマンドを同時に実行します。

    手動で更新

    検討するオプションです。特に、データの読み込みやバッチ更新の場合(たとえば、長期間の後に大量の情報/データのみを読み込むシステム)、データを変更または処理する操作を最後に行うのが一般的であるため、<コードを含めるだけで済みます。>更新 最後に操作します。

    REFRESH操作のスケジュール

    最初の広く使用されているオプションは、スケジューリングシステムを使用して更新を呼び出すことです。たとえば、cronジョブで同様の設定を行うことができます。

    */30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"
    

    その後、マテリアライズドビューは30分ごとに更新されます。

    考慮事項

    このオプションは、特に CONCURRENTLY を使用すると、非常に効果的です。 オプションですが、常に100%最新ではないデータを受け入れることができる場合に限ります。 CONCURRENTLY の有無にかかわらず、 、 REFRESH コマンドはクエリ全体を実行する必要があるため、 REFRESH をスケジュールする時間を検討する前に、内部クエリの実行に必要な時間をとる必要があります。 。

    トリガーで更新

    もう1つのオプションは、 REFRESH MATERIALIZED VIEWを呼び出すことです。 次のようなトリガー関数で:

    CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
    RETURNS trigger LANGUAGE plpgsql AS $$
    BEGIN
        REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
        RETURN NULL;
    END;
    $$;
    

    次に、ビューの変更を含むテーブルで、次のことを行います。

    CREATE TRIGGER tg_refresh_my_mv AFTER INSERT OR UPDATE OR DELETE
    ON table_name
    FOR EACH STATEMENT EXECUTE PROCEDURE tg_refresh_my_mv();
    

    考慮事項

    パフォーマンスと並行性に関するいくつかの重大な落とし穴があります:

    1. INSERT / UPDATE / DELETE操作では、クエリを実行する必要があります(MVを検討している場合は遅くなる可能性があります)。
    2. CONCURRENTLYでも 、1つの REFRESH それでも別のテーブルをブロックするため、関連するテーブルのINSERT / UPDATE/DELETEはシリアル化されます。

    良い考えとして私が考えることができる唯一の状況は、変更が本当にまれであるかどうかです。

    LISTEN/NOTIFYを使用して更新

    前のオプションの問題は、同期的であり、各操作で大きなオーバーヘッドが発生することです。これを改善するには、以前と同じようにトリガーを使用できますが、これは NOTIFYのみを呼び出します。 操作:

    CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
    RETURNS trigger LANGUAGE plpgsql AS $$
    BEGIN
        NOTIFY refresh_mv, 'my_mv';
        RETURN NULL;
    END;
    $$;
    

    したがって、接続を維持し、 LISTENを使用するアプリケーションを構築できます。 REFRESHを呼び出す必要性を識別するための操作 。これをテストするために使用できる優れたプロジェクトの1つはpgsidekickです。このプロジェクトでは、シェルスクリプトを使用して LISTENを実行できます。 、 REFRESHをスケジュールできます として:

    pglisten --listen=refresh_mv --print0 | xargs -0 -n1 -I? psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY ?;"
    

    または、 pglaterを使用します ( pgsidekick内にも ) REFRESHを呼び出さないようにするため よく。たとえば、次のトリガーを使用して、 REFRESHにすることができます。 、ただし1分(60秒)以内:

    CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
    RETURNS trigger LANGUAGE plpgsql AS $$
    BEGIN
        NOTIFY refresh_mv, '60 REFRESH MATERIALIZED VIEW CONCURRENLTY my_mv';
        RETURN NULL;
    END;
    $$;
    

    したがって、 REFRESHは呼び出されません。 60秒以内に、また NOTIFY 60秒以内に何度もREFRESH トリガーされるのは1回だけです。

    考慮事項

    cronオプションとして、これは少し古いデータでむき出しになる場合にのみ有効ですが、これには REFRESHという利点があります。 本当に必要な場合にのみ呼び出されるため、オーバーヘッドが少なくなり、データは必要なときにさらに近く更新されます。

    OBS:私はまだコードと例を試したことがないので、誰かが間違いを見つけたり、タイプミスしたり、試してもうまくいく(またはうまくいかない)場合は、私に知らせてください。



    1. SQL Serverで「smalldatetime」を「time」に変換する(T-SQLの例)

    2. 動的SQLステートメントを使用したカーソルForループ

    3. 制約を変更する方法

    4. 日付範囲から日を生成する