Wie indiziere ich eine Abfrage mit "WHERE field IS NULL"?


13

Ich habe eine Tabelle mit vielen Einfügungen und setze eines der Felder ( uploaded_at) auf NULL. Dann wählt eine periodische Aufgabe alle Tupel aus WHERE uploaded_at IS NULL, verarbeitet sie und aktualisiert sie und stellt sie uploaded_atauf das aktuelle Datum ein.

Wie soll ich die Tabelle indizieren?

Ich verstehe, dass ich einen Teilindex verwenden sollte wie:

CREATE INDEX foo ON table (uploaded_at) WHERE uploaded_at IS NULL

Oder so etwas. Ich bin ein bisschen verwirrt, wenn es richtig ist, ein Feld zu indizieren, das immer ist NULL. Oder ob es richtig ist, einen B-Tree-Index zu verwenden. Hash scheint eine bessere Idee zu sein, ist jedoch veraltet und wird nicht über die Streaming-Hot-Standby-Replikation repliziert. Jeder Rat wäre sehr dankbar.

Ich habe ein bisschen mit den folgenden Indizes experimentiert:

"foo_part" btree (uploaded_at) WHERE uploaded_at IS NULL
"foo_part_id" btree (id) WHERE uploaded_at IS NULL

und der Abfrageplaner scheint immer den foo_partIndex zu wählen . explain analyseergibt auch ein etwas besseres Ergebnis für den foo_partIndex:

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

vs

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

Antworten:


10

In diesem speziellen Fall ist die tatsächlich indizierte Spalte für die vorliegende Abfrage irrelevant. Sie können eine beliebige Spalte auswählen. Ich würde etwas anderes aussuchen als uploaded_at, was nutzlos ist. Einige Spalten, die für andere Abfragen nützlich sein können und im Idealfall nicht größer als 8 Byte sind.

CREATE INDEX foo ON table bar (some_col) WHERE uploaded_at IS NULL;

Wenn Sie keinen Anwendungsfall für eine andere Spalte haben, ist es immer noch am besten, sich an die Unbrauchbaren zu halten uploaded_at, um keine zusätzlichen Wartungskosten für den Index und Einschränkungen für HOT-Updates einzuführen. Mehr:

Oder verwenden Sie eine Konstante als Indexausdruck, wenn Sie keine andere Indexspalte verwenden. Mögen:

CREATE INDEX baz ON table bar ((TRUE)) WHERE uploaded_at IS NULL;

Klammern erforderlich. Dies hält auch den Index auf einer minimalen Größe. Die Indexspalte ist zwar nie größer als 8 Byte (was auch der Fall ist timestamp), hat aber trotzdem eine minimale Größe. Verbunden:


Könnte es idzum Beispiel ein serielles Feld sein?
Kirill Zaitsev

1
@teferi: a serialist so gut wie keine. Der Punkt ist, ob es tatsächlich Abfragen gibt, um davon Gebrauch zu machen.
Erwin Brandstetter
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.