web-dev-qa-db-ja.com

`WHEREフィールドIS NULL`でクエリにインデックスを付ける方法は?

たくさんの挿入があるテーブルがあり、フィールド(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 analysefoo_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
14
Kirill Zaitsev

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

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

他の列のユースケースがない場合でも、役に立たない_uploaded_at_を使用することをお勧めします。そのため、インデックスの追加のメンテナンスコストとH.O.Tの制限を導入しないでください。アップデート。もっと:

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

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

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

10