Warum führt PostgreSQL einen sequentiellen Scan für indizierte Spalten durch?

150

Sehr einfaches Beispiel - eine Tabelle, ein Index, eine Abfrage:

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

gibt mir:

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

Warum wird stattdessen KEIN Index-Scan durchgeführt? Was vermisse ich?

Alex Vayda
quelle

Antworten:

222

Wenn SELECT mehr als ungefähr 5-10% aller Zeilen in der Tabelle zurückgibt, ist ein sequentieller Scan viel schneller als ein Index-Scan.

Dies liegt daran, dass für einen Index-Scan mehrere E / A-Vorgänge für jede Zeile erforderlich sind (suchen Sie die Zeile im Index und rufen Sie sie dann vom Heap ab). Während für einen sequentiellen Scan nur eine einzelne E / A für jede Zeile erforderlich ist - oder sogar weniger, da ein Block (eine Seite) auf der Festplatte mehr als eine Zeile enthält, können mit einer einzelnen E / A-Operation mehr als eine Zeile abgerufen werden.

Übrigens: Dies gilt auch für andere DBMS - einige Optimierungen wie "Nur-Index-Scans" werden beiseite gelegt (aber für ein SELECT * ist es höchst unwahrscheinlich, dass ein solches DBMS für einen "Nur-Index-Scan" verwendet wird).

ein Pferd ohne Name
quelle
12
Die 5-10% hängen von einigen Konfigurationseinstellungen und der Speicherung der Daten ab. Es ist keine harte Zahl.
Frank Heikens
6
@Frank: Deshalb habe ich "ungefähr" gesagt :) Aber danke, dass du darauf hingewiesen hast
du hast
5
Außerdem kann ein sequentieller Scan mehrere Seiten gleichzeitig vom Heap anfordern und den Kernel auffordern, den nächsten Block abzurufen, während er auf dem aktuellen arbeitet. Ein Index-Scan ruft eine Seite gleichzeitig ab. (Ein Bitmap-Scan stellt einen Kompromiss zwischen beiden dar. In einem Plan werden normalerweise Abfragen angezeigt, die für einen Index-Scan nicht selektiv genug, aber dennoch nicht so selektiv sind, dass ein vollständiger Tabellenscan erforderlich ist.)
angezeigt erforderlich ist. araqnid
4
Die interessante Frage ist, woher die Datenbank weiß, wie viele Zeilen die Abfrage zurückgeben wird, ohne dies vorher zu tun. Speichert es Statistiken wie die Anzahl der unterschiedlichen Werte gegenüber der Tabellengröße irgendwo?
Laurent Grégoire
7
@ LaurentGrégoire: Ja, die Datenbank speichert Statistiken über die Anzahl der Zeilen und die Verteilung der Werte. Einzelheiten finden Sie im Handbuch: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name
13

Hast du ANALYSIERT? die Tabelle / Datenbank ? Und was ist mit den Statistiken ? Wenn es viele Datensätze mit einem Jahr> 2009 gibt, ist ein sequentieller Scan möglicherweise schneller als ein Index-Scan.

Frank Heikens
quelle
0

Beim Index-Scan springt der Lesekopf von einer Zeile zur nächsten, was 1000-mal langsamer ist als beim Lesen des nächsten physischen Blocks (beim sequentiellen Scan).

Wenn also die (Anzahl der abzurufenden Datensätze * 1000) geringer ist als die Gesamtzahl der Datensätze, wird der Index-Scan besser ausgeführt.

Gaurav Neema
quelle
0

@a_horse_with_no_name hat es ganz gut erklärt. Auch wenn Sie wirklich einen Index-Scan verwenden möchten, sollten Sie im Allgemeinen begrenzte Bereiche in der where-Klausel verwenden. zB - Jahr> 2019 und Jahr <2020.

In vielen Fällen werden Statistiken für eine Tabelle nicht aktualisiert, und dies ist aufgrund von Einschränkungen möglicherweise nicht möglich. In diesem Fall weiß der Optimierer nicht, wie viele Zeilen er im Jahr> 2019 benötigen soll. Daher wählt er anstelle des vollständigen Wissens einen sequentiellen Scan aus. Begrenzte Partitionen lösen das Problem meistens.

Shitij Goyal
quelle