Pourquoi PostgreSQL effectue-t-il une analyse séquentielle sur une colonne indexée?

151

Exemple très simple - une table, un index, une requête:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

Donne moi:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

Pourquoi n'effectue-t-il PAS d'analyse d'index à la place? Qu'est-ce que je rate?

Alex Vayda
la source

Réponses:

223

Si le SELECT renvoie plus d'environ 5 à 10% de toutes les lignes de la table, une analyse séquentielle est beaucoup plus rapide qu'une analyse d'index.

En effet, une analyse d'index nécessite plusieurs opérations d'E / S pour chaque ligne (recherchez la ligne dans l'index, puis récupérez la ligne dans le tas). Alors qu'une analyse séquentielle ne nécessite qu'un seul E / S pour chaque ligne - ou même moins parce qu'un bloc (page) sur le disque contient plus d'une ligne, donc plus d'une ligne peut être récupérée avec une seule opération d'E / S.

Btw: cela est également vrai pour d'autres SGBD - certaines optimisations comme "index seulement scans" sont supprimées (mais pour un SELECT * il est très peu probable qu'un tel SGBD opte pour un "index seulement scan")

un cheval sans nom
la source
12
Les 5 à 10% dépendent de quelques paramètres de configuration et du stockage des données. Ce n'est pas un chiffre précis.
Frank Heikens
6
@Frank: c'est pourquoi j'ai dit "environ" :) Mais merci de l'avoir signalé
a_horse_with_no_name
5
De plus, une analyse séquentielle peut demander plusieurs pages du tas à la fois, et demander au noyau de récupérer le morceau suivant pendant qu'il travaille sur le morceau actuel - un balayage d'index récupère une page à la fois. (Une analyse bitmap fait un compromis entre les deux, vous voyez généralement qu'apparaître dans un plan pour les requêtes qui ne sont pas suffisamment sélectives pour une analyse d'index, mais pas si sélectives
qu'elles
4
La question intéressante est de savoir comment la base de données sait combien de lignes la requête retournera sans le faire d'abord? Stocke-t-il des statistiques telles que le nombre de valeurs différentes par rapport à la taille de la table quelque part?
Laurent Grégoire
7
@ LaurentGrégoire: oui, la base de données stocke des statistiques sur le nombre de lignes et la distribution des valeurs. Voir le manuel pour plus de détails: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name
13

Avez-vous ANALYSÉ la table / la base de données? Et qu'en est-il des statistiques ? Lorsqu'il existe de nombreux enregistrements dont l'année> 2009, une analyse séquentielle peut être plus rapide qu'une analyse d'index.

Frank Heikens
la source
0

Dans le balayage d'index, la tête de lecture saute d'une ligne à l'autre, ce qui est 1000 fois plus lent que la lecture du bloc physique suivant (dans le balayage séquentiel).

Ainsi, si le (nombre d'enregistrements à récupérer * 1000) est inférieur au nombre total d'enregistrements, l'analyse d'index fonctionnera mieux.

Gaurav Neema
la source
0

@a_horse_with_no_name l'a assez bien expliqué. De plus, si vous souhaitez vraiment utiliser une analyse d'index, vous devez généralement utiliser des plages limitées dans la clause where. par exemple - année> 2019 et année <2020.

La plupart du temps, les statistiques ne sont pas mises à jour sur une table et il peut ne pas être possible de le faire en raison de contraintes. Dans ce cas, l'optimiseur ne saura pas combien de lignes il devrait prendre en année> 2019. Ainsi, il sélectionne une analyse séquentielle au lieu d'une connaissance complète. Les partitions délimitées résoudront le problème la plupart du temps.

Shitij Goyal
la source