Como indexar uma consulta com `WHERE field is NULL`?

13

Eu tenho uma tabela com muitas inserções, definindo um dos campos ( uploaded_at) para NULL. Em seguida, uma tarefa periódica seleciona todas as tuplas WHERE uploaded_at IS NULL, as processa e atualiza, definindo uploaded_ata data atual.

Como devo indexar a tabela?

Entendo que devo usar um índice parcial como:

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

Ou algo assim. Estou um pouco confuso, porém, se é correto indexar em um campo que é sempre NULL. Ou se é correto usar um índice de árvore b. O hash parece uma idéia melhor, mas é obsoleto e não é replicado por meio da replicação de hot-standby de streaming. Qualquer conselho seria muito apreciado.

Eu experimentei um pouco com os seguintes índices:

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

e o planejador de consultas parece sempre escolher o foo_partíndice. explain analysetambém produz um resultado um pouco melhor para o foo_partíndice:

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
fonte

Respostas:

10

Nesse caso especial, a coluna realmente indexada é irrelevante para a consulta em questão. Você pode escolher qualquer coluna. Eu escolheria outra coisa uploaded_atque é inútil. Alguma coluna que pode ser útil para outras consultas e não é maior que 8 bytes, idealmente.

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

Se você não tiver nenhum caso de uso para nenhuma outra coluna, ainda é melhor manter o inútil uploaded_at, para não introduzir custos de manutenção adicionais para o índice e restrições para atualizações HOT. Mais:

Ou use uma constante como expressão de índice, se você não tiver uso para nenhuma outra coluna de índice. Gostar:

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

Parênteses necessários. Isso também mantém o índice no tamanho mínimo. Mas, embora a coluna de índice nunca seja maior que 8 bytes (que é o caso timestamp), ela ainda está no tamanho mínimo. Palavras-chave:

Erwin Brandstetter
fonte
Poderia ser um idcampo serial , por exemplo?
Kirill Zaitsev
1
@teferi: a serialé tão bom quanto qualquer outro. A questão é se realmente existem consultas para fazer uso dela.
precisa