Учитывая таблицу:
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)
Таблица содержит 20 миллионов записей, что, по большому счету , не так много. Но это делает последовательное сканирование медленным.
Как я могу получить последнюю запись ( max(created_at)
) каждого equipment_id
?
Я пробовал оба следующих запроса, с несколькими вариантами, которые я прочитал во многих ответах на эту тему:
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;
Я также пытался создать индексы btree для, equipment_id,created_at
но Postgres обнаружил, что использование seqscan быстрее. Принудительное enable_seqscan = off
использование также бесполезно, поскольку чтение индекса происходит так же медленно, как и сканирование seq, возможно, и хуже.
Запрос должен выполняться периодически, возвращая всегда последний.
Использование Postgres 9.3.
Объясните / проанализируйте (с 1,7 миллионами записей):
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
значений вequipment_id
ожидаемом проценте ниже 0,1%Ответы:
Простой многоколонный индекс b-дерева должен работать в конце концов:
Почему
DESC NULLS LAST
?функция
Если вы не можете разобраться в планировщике запросов, функция, проходящая по таблице оборудования, должна помочь. Поиск по одному equipment_id за раз использует индекс. Для небольшого числа (57, судя по вашему
EXPLAIN ANALYZE
выводу) это быстро.Можно предположить, что у вас есть
equipment
стол?Делает для приятного звонка тоже:
Коррелированные подзапросы
Если подумать, используя эту
equipment
таблицу, вы можете получить грязную работу с низкокоррелированными подзапросами с большим эффектом:Производительность очень хорошая.
LATERAL
присоединиться к Postgres 9.3+Детальное объяснение:
Производительность аналогична коррелированному подзапросу. Сравнение производительности
max()
,DISTINCT ON
, функция, коррелируют подзапрос иLATERAL
в этом:SQL Fiddle .
источник
Попытка 1
Если
equipment
таблица, иgeoposition_records(equipment_id, created_at desc)
тогда у меня работает следующее:
Я не смог заставить PG сделать быстрый запрос , чтобы определить , как список
equipment_id
с и связанным с этимmax(created_at)
. Но я собираюсь попробовать завтра!Попытка 2
Я нашел эту ссылку: http://zogovic.com/post/44856908222/optimizing-postgresql-query-for-distinct-values Комбинируя эту технику с моим запросом из попытки 1, я получаю:
и это работает БЫСТРО! Но вам нужно
geoposition_records(equipment_id, created_at desc)
.источник