Comment indexer une requête avec `WHERE field IS NULL`?

14

J'ai une table avec beaucoup d'insertions, définissant l'un des champs ( uploaded_at) sur NULL. Une tâche périodique sélectionne ensuite tous les tuples WHERE uploaded_at IS NULL, les traite et les met à jour, en définissant uploaded_atla date actuelle.

Comment dois-je indexer la table?

Je comprends que je devrais utiliser un index partiel comme:

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

Ou quelque chose comme ça. Je suis un peu confus cependant s'il est correct d'indexer sur un champ qui l'est toujours NULL. Ou s'il est correct d'utiliser un index b-tree. Le hachage semble être une meilleure idée, mais il est obsolète et n'est pas répliqué via la réplication de secours à chaud. Tout avis serait grandement apprécié.

J'ai un peu expérimenté les indices suivants:

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

et le planificateur de requêtes semble toujours choisir l' foo_partindex. explain analysedonne également un résultat légèrement meilleur pour l' foo_partindice:

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

contre

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
la source

Réponses:

10

Dans ce cas particulier, la colonne réellement indexée n'est pas pertinente pour la requête en cours. Vous pouvez choisir n'importe quelle colonne. Je choisirais autre chose que uploaded_at, ce qui est inutile. Une colonne qui peut être utile pour d'autres requêtes et qui ne dépasse pas 8 octets, idéalement.

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

Si vous n'avez aucun cas d'utilisation pour une autre colonne, il est toujours préférable de rester avec l'inutile uploaded_at, donc de ne pas introduire de coûts de maintenance supplémentaires pour l'index et de restrictions pour les mises à jour HOT. Plus:

Ou utilisez une constante comme expression d'index si vous n'avez aucune utilité pour une autre colonne d'index. Comme:

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

Parenthèses requises. Cela maintient également l'index à sa taille minimale. Mais bien que la colonne d'index ne soit jamais supérieure à 8 octets (ce qui est le cas timestamp), elle est toujours de taille minimale de toute façon. En relation:

Erwin Brandstetter
la source
Serait-ce idpar exemple un champ série ?
Kirill Zaitsev
1
@teferi: a serialest aussi bon que n'importe lequel. Le point est de savoir s'il existe réellement des requêtes pour l'utiliser.
Erwin Brandstetter