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

PostgreSQLの複数列の部分インデックスに日時制約を追加する

    now()を使用すると例外が発生します 関数がIMMUTABLEではないため (明らかに)そして、マニュアルを引用します

    (はるかに効率的な)部分インデックスを利用する2つの方法があります:

    1。 定数を使用した条件付きの部分インデックス 日付:

    CREATE INDEX queries_recent_idx ON queries_query (user_sid, created)
    WHERE created > '2013-01-07 00:00'::timestamp;
    

    想定 created 実際にはtimestampとして定義されています timestampを提供することはできません timestamptzの定数 列(timestamp with time zone )。 timestampからのキャスト timestamptzへ (またはその逆)現在のタイムゾーン設定に依存し、不変ではありません 。一致するデータ型の定数を使用します。タイムゾーンがある場合とない場合のタイムスタンプの基本を理解する:

    ドロップして再作成 トラフィックが少ない時間帯のインデックス、おそらく毎日または毎週のcronジョブ(またはあなたにとって十分なもの)。インデックスの作成は非常に高速で、特に部分インデックスは比較的小さいです。このソリューションでも、テーブルに何も追加する必要はありません。

    同時アクセスなしを想定 テーブルに対して、自動インデックス再作成は次のような関数で実行できます:

    CREATE OR REPLACE FUNCTION f_index_recreate()
      RETURNS void
      LANGUAGE plpgsql AS
    $func$
    BEGIN
       DROP INDEX IF EXISTS queries_recent_idx;
       EXECUTE format('
          CREATE INDEX queries_recent_idx
          ON queries_query (user_sid, created)
          WHERE created > %L::timestamp'
        , LOCALTIMESTAMP - interval '30 days');  -- timestamp constant
    --  , now() - interval '30 days');           -- alternative for timestamptz
    END
    $func$;
    

    電話:

    SELECT f_index_recreate();
    

    now() (あなたが持っていたように)はCURRENT_TIMESTAMPと同等です timestamptzを返します 。 timestampにキャストします now()::timestampを使用 またはLOCALTIMESTAMPを使用します 代わりに。

    db <> fiddle こちら
    古い sqlfiddle

    同時アクセスに対処する必要がある場合 テーブルに、DROP INDEX CONCURRENTLYを使用します およびCREATE INDEX CONCURRENTLY 。ただし、これらのコマンドを関数にラップすることはできません。ドキュメントごと

    したがって、2つの別々のトランザクション

    CREATE INDEX CONCURRENTLY queries_recent_idx2 ON queries_query (user_sid, created)
    WHERE  created > '2013-01-07 00:00'::timestamp;  -- your new condition
    

    次に:

    DROP INDEX CONCURRENTLY IF EXISTS queries_recent_idx;
    

    必要に応じて、古い名前に名前を変更します:

    ALTER INDEX queries_recent_idx2 RENAME TO queries_recent_idx;
    

    2。 「アーカイブされた」タグを条件とする部分インデックス

    archivedを追加します テーブルにタグを付ける:

    ALTER queries_query ADD COLUMN archived boolean NOT NULL DEFAULT FALSE;
    

    UPDATE 古い行を「廃止」し、次のようなインデックスを作成するために、選択した間隔で列を作成します。

    CREATE INDEX some_index_name ON queries_query (user_sid, created)
    WHERE NOT archived;
    

    クエリに一致条件を追加して(冗長に見える場合でも)、インデックスを使用できるようにします。 EXPLAIN ANALYZEで確認してください クエリプランナーがキャッチするかどうか-新しい日付のクエリにインデックスを使用できる必要があります。ただし、正確に一致しない、より複雑な条件は理解できません。

    インデックスを削除して再作成する必要はありませんが、UPDATE テーブル上では、インデックスの再作成よりも費用がかかる可能性があり、テーブルは少し大きくなります。

    最初で行きます オプション(インデックスの再作成)。実際、私はこのソリューションをいくつかのデータベースで使用しています。 2つ目は、よりコストのかかる更新が発生します。

    どちらのソリューションも時間の経過とともにその有用性を維持し、より古い行がインデックスに含まれるため、パフォーマンスは徐々に低下します。




    1. T-SQLで日付順に並べ替える方法

    2. 複数の値を持つ動的ドロップダウンボックス用に事前に選択された値

    3. LAMPアプリケーションでのSQLインジェクションをどのように防止しますか?

    4. マージ結合連結によるソートの回避