Kann PostgreSQL Nullen in seinen Indizes verwenden?


10

Ich habe dieses Buch gelesen, in dem das steht

Die Datenbank geht davon aus, dass Indexed_Col IS NOT NULL einen zu großen Bereich abdeckt, um nützlich zu sein, sodass die Datenbank unter dieser Bedingung nicht zu einem Index fährt.

Ich erkenne, dass das Buch mehr als 10 Jahre alt ist, aber es hat sich bereits als sehr nützlich erwiesen. Mit Hilfe der Anweisungen auf den Seiten habe ich eine Abfrage um den Faktor zehn beschleunigt.

Außerdem habe ich beim Ausführen EXPLAIN ANALYZEeiner SELECTAbfrage festgestellt, dass keiner meiner Indizes verwendet wird, auch wenn dies mit allen Rechten der Fall sein sollte.

Meine Frage lautet also:

Angenommen, es gibt eine Tabelle mit einer Spalte, deren Spaltendefinition "NOT NULL" enthält, und es gibt einen Index, der diese Spalte abdeckt. Würde dieser Index in einer Abfrage dieser Tabelle verwendet, in der die Spalten Teil der Abfrage sind?

Mögen:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Antworten:


9

PostgreSQL kann sicherlich einen Index für verwenden IS NOT NULL. Ich sehe auch keine Annahmen des Abfrageplaners zu dieser Bedingung.

Wenn der Nullanteil für die Spalte ( pg_statistic.stanullfrac) niedrig genug ist, um darauf hinzuweisen, dass der Index für die Abfrage sinnvoll selektiv ist, verwendet PostgreSQL einen Index.

Ich kann nicht herausfinden, womit Sie sagen wollen:

Wenn dies korrekt ist, kann nach meinem Verständnis ein Index für eine als "NOT NULL" definierte Spalte nicht in einer Abfrage verwendet werden, die diese Spalte verwendet?

Sicherlich wird ein Index nicht für eine IS NOT NULLBedingung in einer NOT NULLSpalte verwendet. Es würde immer 100% der Zeilen entsprechen, so dass ein Seqscan fast immer viel schneller ist.

PostgreSQL verwendet keinen Index, wenn der Index nicht einen großen Teil der Zeilen für eine Abfrage herausfiltert. Die einzige wahrscheinliche Ausnahme ist, wenn Sie nach einer Reihe von Spalten fragen, die von einem einzelnen Index in einer Reihenfolge abgedeckt werden, die der des Index entspricht. PostgreSQL führt dann möglicherweise nur einen Index-Scan durch. ZB wenn es einen Index gibt t(a, b, c)und Sie:

select a, b FROM t ORDER BY a, b, c;

PostgreSQL verwendet möglicherweise Ihren Index, obwohl keine Zeilen herausgefiltert werden, da nur der Index gelesen werden muss und das Lesen des Heaps übersprungen werden kann, eine Sortierung vermieden werden kann usw.


Dies gilt ab PG 9.0
Eradman

1
Und selbst in einer nullbaren Spalte verwendet eine Abfrage mit Bedingung WHERE column IS NOT NULLmöglicherweise nicht den Index, da, wie im Buch angegeben, "ein zu großer Bereich abgedeckt wird, um nützlich zu sein". Wenn 90% der Werte nicht null sind, ist ein Seqscan wahrscheinlich auch schneller.
Ypercubeᵀᴹ

Genau. Es könnte sein, aber nur, wenn ein großer Teil der Tabelle null ist. Oft in diesem Fall ein Teilindex ist eine bessere Wahl sowieso.
Craig Ringer

Ja. Ich habe versucht zu sagen, dass (so wie ich es verstehe) der Teil "einen zu großen Bereich abdeckt" sich auf den Index bezieht, aber in Bezug auf die spezifische Bedingung und nicht auf den Index im Allgemeinen.
Ypercubeᵀᴹ

2
@FuriousFolder Heh, hier gibt es zu viele Negationen. PostgreSQL verwendet keinen Index für eine NOT NULLSpalte für eine IS NOT NULLAbfrage, es sei denn, dieser Index ist auch für andere Teile der WHEREKlausel, Verknüpfungsfilter usw. nützlich oder kann für einen geordneten Nur-Index-Scan verwendet werden. Mit anderen Worten, die Redundanz IS NOT NULLin der NOT NULLSpalte wird vollständig ignoriert und die Indexverwendung wird anhand anderer Details ausgewählt. (Siehe Bearbeiten, nur Index-Scans).
Craig Ringer

2

Zusätzlich zu Craigs gründlicher Antwort wollte ich hinzufügen, dass auf dem Cover des Buches, auf das Sie verweisen, steht:

Deckt Oracle, DB2 und SQL Server ab

Daher würde ich nicht darauf vertrauen, dass es eine gute Quelle für Ratschläge insbesondere zu PostgreSQL ist. Jedes RDBMS kann überraschend anders sein!

Ich bin ein wenig verwirrt über Ihre ursprüngliche Frage, aber hier ist ein Beispiel, das zeigt, dass der Abschnitt des Buches nicht 100% korrekt ist. Um weitere Verwirrung zu vermeiden, finden Sie hier den gesamten relevanten Absatz in der Google Buchsuche .

Die Datenbank geht davon aus, dass Indexed_Col IS NOT NULL einen zu großen Bereich abdeckt, um nützlich zu sein, sodass die Datenbank unter dieser Bedingung nicht zu einem Index fährt. In seltenen Fällen ist ein Nicht-Null-Wert so selten, dass ein Indexbereichsscan über alle möglichen Nicht-Null-Werte von Vorteil ist. Wenn Sie in solchen Fällen eine sichere Unter- oder Obergrenze für den Bereich aller möglichen Werte ermitteln können, können Sie einen Bereichsscan mit einer Bedingung wie Positive_ID_Column> -1 oder Date_Column> TO_DATE ('0001/01/01' aktivieren). , 'JJJJ / MM / TT').

Postgres kann tatsächlich (im folgenden erfundenen Fall) einen Index verwenden, um IS NOT NULLAbfragen zu erfüllen, ohne Range-Scan-Kludges wie die vorgeschlagenen hinzuzufügen Positive_ID_Column > -1. In den Kommentaren zu Craigs Fragen, warum Postgres diesen Index in diesem speziellen Fall auswählt, und im Hinweis zur Verwendung von Teilindizes.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Dies ist übrigens Postgres 9.3, aber ich glaube, dass die Ergebnisse unter 9.1 ungefähr ähnlich wären, obwohl kein "Nur-Index-Scan" verwendet würde.

Bearbeiten: Ich sehe, Sie haben Ihre ursprüngliche Frage geklärt, und Sie fragen sich anscheinend, warum Postgres in einem einfachen Beispiel keinen Index verwendet, wie:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Wahrscheinlich, weil Sie keine Zeilen in der Tabelle haben. Fügen Sie also einige Testdaten hinzu und ANALYZE my_table;.


In der Beschreibung dieses Buches (Schwerpunkt Mine): "Der Autor Dan Tow skizziert eine zeitsparende Methode, die er entwickelt hat, um den optimalen Ausführungsplan schnell und systematisch zu finden, unabhängig von der Komplexität des verwendeten SQL oder der verwendeten Datenbankplattform. " vielleicht übersehen Sie # 1 der Frage, nämlich, dass die Säule wird definiert als NOT NULL, nicht , dass die Abfrage verwendet IS NOT NULLals Index Zustand. Dies steht in den Kommentaren, auf die Sie verwiesen haben, aber ich werde die Frage aktualisieren, um sie aufzunehmen.
FuriousFolder

Außerdem ist das Buch selbst sprachunabhängig: Die einzigen DMBS-spezifischen Teile befassen sich mit der Anzeige von Abfrageplänen, was Postgres ganz einfach macht :)
FuriousFolder

1
@FuriousFolder Die Spalte ist als NICHT NULL definiert, aber dieser Teil (in Ihrer Frage aus dem Buch): "dass Indexed_Col NICHT NULL abdeckt ..." bezieht sich auf die where-Bedingung und nicht auf die Spaltendefinition . Obwohl es schwer zu sein ist, weil es außerhalb des Kontexts ist. Vielleicht sollten Sie den gesamten (vorhergehenden) Absatz aus dem Buch aufnehmen.
Ypercubeᵀᴹ

-1

Sie haben Ihre Abfrage- oder Beispieldaten nicht veröffentlicht. Der häufigste Grund, warum Indizes nicht verwendet werden, hängt jedoch mit dem Volumen zusammen.

Indizes sind wie ein Telefonbuch, das eine Spalte in eine Zeilenposition übersetzt. Wenn Sie nur nach wenigen Zeilen suchen, ist es sinnvoll, jede Zeile im Telefonbuch und dann die Zeile in der Haupttabelle nachzuschlagen.

Bei mehr als ein paar Zeilen ist es jedoch billiger, das Telefonbuch zu überspringen und alle Zeilen in der Haupttabelle zu durchlaufen. Nach meiner Erfahrung liegt der Wendepunkt bei etwa 100 Zeilen.


"Indizes sind wie ein Telefonbuch, das eine Spalte in eine Zeilenposition übersetzt. Wenn Sie nur nach wenigen Zeilen suchen, ist es sinnvoll, jede Zeile im Telefonbuch und dann die Zeile in der Haupttabelle nachzuschlagen." Tatsächlich sind Indizes wie kleinere Telefonbücher, die jedes Mal aktualisiert werden, wenn das von ihnen indizierte Telefonbuch aktualisiert wird. Sie wissen, dass Sie jedes Mal, wenn Sie ein kleineres Telefonbuch öffnen, alle Informationen finden, die in der Indizierungsbedingung beschrieben werden. ZB Alle Personen mit dem Namen 'frank' in einer Indextabelle : CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder

Dies ermöglicht ein Index-Only - Scan zu sein , viel viel schneller, da man das ganze „kleine Telefonbuch“ in dem Speicher lesen kann, was nicht machbar mit einem Multi-Millionen - ausgekleideten Tisch ist.
FuriousFolder

@FuriousFolder: Sie beschreiben einen Nur-Index-Scan. Das OP sagt jedoch, dass seine Indizes nicht verwendet werden, was nicht passieren würde, wenn ein Nur-Index-Scan die Abfrage erfüllen würde.
Andomar

Andomar ... Ich bin der OP, haha. Mein Ziel ist genau das; Damit diese Abfrage einen Nur-Index-Scan verwendet. Ich habe es seit erreicht, da Craig erklärte , dass Postgres ist die Lage , einen Index für eine Spalte zu verwenden , wo die Spaltendefinition umfasst NOT NULL
FuriousFolder
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.