Biorąc pod uwagę tabelę:
Column | Type
id | integer
latitude | numeric(9,6)
longitude | numeric(9,6)
speed | integer
equipment_id | integer
created_at | timestamp without time zone
Indexes:
"geoposition_records_pkey" PRIMARY KEY, btree (id)
Tabela zawiera 20 milionów rekordów, co nie jest stosunkowo dużą liczbą. Powoduje to jednak spowolnienie skanowania sekwencyjnego.
Jak mogę uzyskać ostatni rekord ( max(created_at)
) każdego z nich equipment_id
?
Próbowałem obu poniższych zapytań, z kilkoma wariantami, które przeczytałem w wielu odpowiedziach na ten temat:
select max(created_at),equipment_id from geoposition_records group by equipment_id;
select distinct on (equipment_id) equipment_id,created_at
from geoposition_records order by equipment_id, created_at desc;
Próbowałem również utworzyć indeksy btree dla, equipment_id,created_at
ale Postgres odkrył, że użycie seqscan jest szybsze. Wymuszanie również enable_seqscan = off
nie ma sensu, ponieważ odczyt indeksu jest tak wolny jak skanowanie seq, prawdopodobnie gorszy.
Kwerenda musi być uruchamiana okresowo, zwracając zawsze ostatnią.
Korzystanie z Postgres 9.3.
Wyjaśnij / przeanalizuj (z 1,7 mln rekordów):
set enable_seqscan=true;
explain analyze select max(created_at),equipment_id from geoposition_records group by equipment_id;
"HashAggregate (cost=47803.77..47804.34 rows=57 width=12) (actual time=1935.536..1935.556 rows=58 loops=1)"
" -> Seq Scan on geoposition_records (cost=0.00..39544.51 rows=1651851 width=12) (actual time=0.029..494.296 rows=1651851 loops=1)"
"Total runtime: 1935.632 ms"
set enable_seqscan=false;
explain analyze select max(created_at),equipment_id from geoposition_records group by equipment_id;
"GroupAggregate (cost=0.00..2995933.57 rows=57 width=12) (actual time=222.034..11305.073 rows=58 loops=1)"
" -> Index Scan using geoposition_records_equipment_id_created_at_idx on geoposition_records (cost=0.00..2987673.75 rows=1651851 width=12) (actual time=0.062..10248.703 rows=1651851 loops=1)"
"Total runtime: 11305.161 ms"
NULL
wartości wequipment_id
oczekiwanym procencie poniżej 0,1%Odpowiedzi:
W końcu powinien działać zwykły wielokolumnowy indeks b-drzewa:
Dlaczego
DESC NULLS LAST
?Funkcjonować
Jeśli nie możesz mówić rozsądnie w narzędziu do planowania zapytań, funkcja zapętlająca tabelę wyposażenia powinna załatwić sprawę. Wyszukiwanie jednego id_urządzenia na raz korzysta z indeksu. W przypadku małej liczby (57 sądząc po
EXPLAIN ANALYZE
wynikach) jest to szybkie.Można bezpiecznie założyć, że masz
equipment
stolik?Sprawia również, że jest to miły telefon:
Skorelowane podzapytania
Pomyśl o tym, korzystając z tej
equipment
tabeli, możesz wykonać brudną pracę z mało skorelowanymi podkwerendami, aby uzyskać doskonały efekt:Wydajność jest bardzo dobra.
LATERAL
dołącz do Postgres 9.3+Szczegółowe wyjaśnienie:
Podobna wydajność jak skorelowane podzapytanie. Porównywanie wydajności
max()
,DISTINCT ON
, funkcja, skorelowane podzapytania iLATERAL
w ten sposób:SQL Fiddle .
źródło
Próba 1
Gdyby
equipment
stolik igeoposition_records(equipment_id, created_at desc)
to dla mnie działa:
Nie byłem w stanie zmusić PG do wykonania szybkiego zapytania w celu ustalenia zarówno listy
equipment_id
s, jak i pokrewnychmax(created_at)
. Ale jutro spróbuję ponownie!Próba 2
Znalazłem ten link: http://zogovic.com/post/44856908222/optimizing-postgresql-query-for-distinct-values Łącząc tę technikę z moim zapytaniem z próby 1, otrzymuję:
i to działa SZYBKO! Ale ty potrzebujesz
geoposition_records(equipment_id, created_at desc)
.źródło