如何使用`WHERE field IS NULL`索引查询?

Kir*_*sev 15 postgresql index null index-tuning

我有一个包含大量插入内容的表,将其中一个字段 ( uploaded_at) 设置为NULL. 然后周期性任务选择所有元组WHERE uploaded_at IS NULL,处理它们并更新,设置uploaded_at为当前日期。

我应该如何索引表?

我知道我应该使用部分索引,例如:

CREATE INDEX foo ON table (uploaded_at) WHERE uploaded_at IS NULL
Run Code Online (Sandbox Code Playgroud)

或者像那样。我有点困惑,但如果在始终为NULL. 或者如果使用 b 树索引是正确的。Hash 看起来是一个更好的主意,但它已经过时并且不能通过流式热备复制进行复制。任何建议将不胜感激。

我对以下索引进行了一些试验:

"foo_part" btree (uploaded_at) WHERE uploaded_at IS NULL
"foo_part_id" btree (id) WHERE uploaded_at IS NULL
Run Code Online (Sandbox Code Playgroud)

并且查询平面似乎总是选择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
Run Code Online (Sandbox Code Playgroud)

对比

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
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 11

在这种特殊情况下,实际索引的列与手头的查询无关。您可以选择任何列。我会选择除 之外的其他东西uploaded_at,这是无用的。某些列可能对其他查询有用,理想情况下不大于 8 个字节。

CREATE INDEX foo ON table bar (some_col) WHERE uploaded_at IS NULL;
Run Code Online (Sandbox Code Playgroud)

如果你没有任何其他列的用例,最好还是坚持使用无用的uploaded_at,这样就不要为索引引入额外的维护成本和对 HOT 更新的限制。更多的:

或者,如果您没有使用任何其他索引列,则使用常量作为索引表达式。喜欢:

CREATE INDEX baz ON table bar ((TRUE)) WHERE uploaded_at IS NULL;
Run Code Online (Sandbox Code Playgroud)

需要括号。这也使索引保持在最小大小。但是,尽管索引列永远不会大于 8 个字节(对于 而言就是这种情况timestamp),它仍然处于最小大小。有关的: