Analyse Seq inattendue lors d'une requête contre un booléen avec la valeur NULL


10

J'ai une colonne de base de données appelée auto_reviewoù est le type de colonne boolean. Il existe un index pour ce champ, créé à l'aide de l'ORM ActiveRecord.

CREATE INDEX index_table_on_auto_renew ON table USING btree (auto_renew);

Lorsque j'interroge le champ pour une valeur booléenne, PG utilise l'index comme prévu.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" = 'f'
                                          QUERY PLAN
----------------------------------------------------------------------------------------------
 Bitmap Heap Scan on table  (cost=51.65..826.50 rows=28039 width=186)
   Filter: (NOT auto_renew)
   ->  Bitmap Index Scan on index_domains_on_auto_renew  (cost=0.00..44.64 rows=2185 width=0)
         Index Cond: (auto_renew = false)
(4 rows)

Lorsque la valeur est NULL, un balayage séquentiel est utilisé.

EXPLAIN for: SELECT "table".* FROM "table"  WHERE "table"."auto_renew" IS NULL
                           QUERY PLAN
----------------------------------------------------------------
 Seq Scan on table  (cost=0.00..1094.01 rows=25854 width=186)
   Filter: (auto_renew IS NULL)
(2 rows)

Je suis curieux de connaître la raison de ce choix.

Réponses:


19

Généralement, col IS NULLest un candidat possible pour une recherche d'index b-tree (par défaut).Le manuel :

De plus, un IS NULLIS NOT NULL condition ou sur une colonne d'index peut être utilisée avec un index B-tree.

Pour obtenir une preuve, désactivez les analyses séquentielles (dans une session de test uniquement!):

SET enable_seqscan = OFF;

Je cite le manuel ici :

enable_seqscan (boolean)

Active ou désactive l'utilisation par le planificateur de requêtes de types de plan d'analyse séquentielle. Il est impossible de supprimer complètement les analyses séquentielles, mais la désactivation de cette variable décourage le planificateur d'en utiliser une s'il existe d'autres méthodes. La valeur par défaut est activée.

Réessayez ensuite:

EXPLAIN ANALYZE SELECT * FROM tbl WHERE auto_renew IS NULL;

Cela entraînera probablement une analyse d'index bitmap plus lente qu'une analyse séquentielle sur la table.

Réinitialisez ou fermez la session (le paramètre est local à la session).

RESET enable_seqscan;

Les index sur les booleancolonnes ne sont utiles que dans certains cas. Le planificateur n'utilise un index que s'il s'attend à ce que ce soit plus rapide. Les calculs sont basés sur vos paramètres de coût et les statistiques recueillies parANALYZE . Si une partie importante du tableau correspond à votre condition (environ 5% ou plus, cela dépend), il est généralement plus rapide de faire une analyse complète du tableau à la place.

Cela laisse la valeur rare dans une booleancolonne comme le seul candidat utile pour un index simple. Et il est généralement plus efficace de créer un index partiel (plus spécialisé) place pour cela - qui est moins cher à maintenir, plus petit, plus rapide et utilisé plus facilement si les conditions de requête correspondent.

Si vous avez beaucoup de requêtes à la recherche de lignes avec auto_renew IS NULLet que le NULLcas n'est pas très courant (et / ou vous avez besoin d'un certain ordre de tri), cet index vous aidera à trouver / trier ces lignes rapidement:

CREATE INDEX index_tbl_tbl_id_auto_renew_null ON tbl (tbl_id)
WHERE auto_renew IS NULL;

La condition de l'index partiel doit être répétée dans la WHEREclause d'une requête plus ou moins exactement pour que le planificateur de requêtes réalise que l'index est applicable.

La colonne indexée ( tbl_id) est un choix arbitraire. La partie importante est la WHEREclause. Cet index particulier serait plus efficace pour les requêtes avec ORDER BY tbl_idou un filtre supplémentaire ou une jointure tbl_id. Vous pouvez en faire un index multicolonne . Les colonnes booléennes sont souvent plus utiles en combinaison avec d'autres.

À part: les ORM sont des béquilles qui ne parviennent pas régulièrement à tirer le plein potentiel de votre SGBDR.


Brillante réponse, merci Erwin. Je suis triste de ne pas pouvoir voter deux fois.
Simone Carletti
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.