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 here
Old sqlfiddle
テーブルへの同時アクセスを処理する必要がある場合は、とを使用DROP INDEX CONCURRENTLY
しCREATE INDEX CONCURRENTLY
ます。ただし、ドキュメントによると、これらのコマンドを関数にラップすることはできません。
...通常のCREATE INDEX
コマンドはトランザクションブロック内で実行できますが、実行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つ目は、よりコストのかかる更新が発生します。
どちらのソリューションも時間の経過とともにその有用性を維持し、より古い行がインデックスに含まれるため、パフォーマンスは徐々に低下します。