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
Kirill Zaitsev
quelle

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:

Erwin Brandstetter
quelle
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