Bagaimana cara mengindeks kueri dengan `WHERE is IS NULL`?

14

Saya punya tabel dengan banyak sisipan, mengatur salah satu bidang ( uploaded_at) ke NULL. Kemudian tugas berkala memilih semua tupel WHERE uploaded_at IS NULL, memprosesnya dan memperbarui, mengatur uploaded_atke tanggal saat ini.

Bagaimana saya harus mengindeks tabel?

Saya mengerti bahwa saya harus menggunakan indeks parsial seperti:

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

Atau pertanda seperti itu. Saya agak bingung meskipun apakah itu benar untuk mengindeks pada bidang yang selalu NULL. Atau jika benar menggunakan indeks b-tree. Hash terlihat seperti ide yang lebih baik, tetapi sudah usang dan tidak direplikasi melalui streaming replikasi hot-standby. Saran apa pun akan sangat dihargai.

Saya telah bereksperimen sedikit dengan indeks berikut:

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

dan perencana kueri tampaknya selalu memilih foo_partindeks. explain analysejuga menghasilkan hasil yang sedikit lebih baik untuk foo_partindeks:

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

vs.

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
Kirill Zaitsev
sumber

Jawaban:

10

Dalam kasus khusus ini, kolom yang diindeks sebenarnya tidak relevan untuk kueri. Anda dapat memilih kolom mana saja. Saya akan memilih sesuatu yang lain daripada uploaded_at, yang tidak berguna. Beberapa kolom yang mungkin berguna untuk permintaan lain dan tidak lebih besar dari 8 byte, idealnya.

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

Jika Anda tidak menggunakan kasing untuk kolom lainnya, tetap yang terbaik adalah tetap menggunakan yang tidak berguna uploaded_at, jadi jangan masukkan biaya pemeliharaan tambahan untuk indeks dan pembatasan untuk pembaruan HOT. Lebih:

Atau gunakan konstanta sebagai ekspresi indeks jika Anda tidak menggunakan kolom indeks lainnya. Suka:

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

Diperlukan tanda kurung. Ini juga menjaga indeks pada ukuran minimum. Tetapi sementara kolom indeks tidak pernah lebih besar dari 8 byte (yang merupakan kasus untuk timestamp) itu masih pada ukuran minimum. Terkait:

Erwin Brandstetter
sumber
Mungkinkah itu menjadi idbidang serial misalnya?
Kirill Zaitsev
1
@teferi: a serialsebagus apapun. Intinya adalah apakah sebenarnya ada pertanyaan untuk memanfaatkannya.
Erwin Brandstetter