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
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: