web-dev-qa-db-fra.com

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

J'ai une table avec beaucoup d'inserts, définissant l'un des champs (uploaded_at) à NULL. Ensuite, une tâche périodique sélectionne tous les tuples WHERE uploaded_at IS NULL, les traite et les met à jour, en définissant uploaded_at à la 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 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 le foo_part index. explain analyse donne également un résultat légèrement meilleur pour le foo_part index:

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

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 s'en tenir à l'inutile uploaded_at, Afin de ne pas introduire de coûts de maintenance supplémentaires pour l'index et des restrictions pour H.O.T. mises à jour. Plus:

Ou utilisez un constant 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 pour timestamp), elle est quand même de taille minimale. En relation:

10
Erwin Brandstetter