「WHERE field IS NULL」でクエリにインデックスを付ける方法は?


13

多数の挿入を含むテーブルがあり、フィールド(uploaded_at)の1つをに設定していNULLます。次に、定期タスクがすべてのタプルを選択し、WHERE uploaded_at IS NULLそれらを処理して更新し、uploaded_at現在の日付に設定します。

テーブルにインデックスを付けるにはどうすればよいですか?

次のような部分インデックスを使用する必要があることを理解しています。

CREATE INDEX foo ON table (uploaded_at) WHERE uploaded_at IS NULL

またはそのようなsmth。しかし、常にフィールドにインデックスを付けることが正しい場合、私は少し混乱していますNULL。または、bツリーインデックスを使用することが正しい場合。ハッシュはより良いアイデアのように見えますが、廃止されており、ストリーミングホットスタンバイレプリケーションを介してレプリケートされません。どんなアドバイスも大歓迎です。

私は次のインデックスで少し実験しました:

"foo_part" btree (uploaded_at) WHERE uploaded_at IS NULL
"foo_part_id" btree (id) WHERE uploaded_at IS NULL

クエリプランナーは常にfoo_partインデックスを選択するようです。explain analyseまた、foo_partインデックスの結果が若干良くなります:

Index Scan using foo_part on t1  (cost=0.28..297.25 rows=4433 width=16) (actual time=0.025..3.649 rows=4351 loops=1)
   Index Cond: (uploaded_at IS NULL)
 Total runtime: 4.060 ms

Bitmap Heap Scan on t1  (cost=79.15..6722.83 rows=4433 width=16) (actual time=1.032..4.717 rows=4351 loops=1)
   Recheck Cond: (uploaded_at IS NULL)
   ->  Bitmap Index Scan on foo_part_id  (cost=0.00..78.04 rows=4433 width=0) (actual time=0.649..0.649 rows=4351 loops=1)
 Total runtime: 5.131 ms

回答:


10

この特別なケースでは、実際にインデックス付けされた列は、手元のクエリとは無関係です。任意の列を選択できます。uploaded_at役に立たない以外のものを選びます。他のクエリに役立つ可能性があり、8バイト以下の列が理想的です。

CREATE INDEX foo ON table bar (some_col) WHERE uploaded_at IS NULL;

他の列のユースケースがない場合でもuploaded_at、インデックスのメンテナンスコストとHOT更新の制限を追加しないように、引き続きuselessを使用することをお勧めします。もっと:

または、他のインデックス列を使用しない場合は、インデックス式として定数を使用します。お気に入り:

CREATE INDEX baz ON table bar ((TRUE)) WHERE uploaded_at IS NULL;

括弧が必要です。これにより、インデックスも最小サイズに維持されます。ただし、インデックス列が8バイトより大きくなることはありませんが(これはの場合timestamp)、とにかく最小サイズのままです。関連:


idたとえば、シリアルフィールドでしょうか?
キリルザイツェフ14年

1
@teferi:a serialはどんなものよりも優れています。ポイントは、それを実際に使用するクエリがあるかどうかです。
アーウィンブランドステッター14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.