Given the table:
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)
The table has 20 million records that is not, relatively speaking, a large number. But it makes sequential scans slow.
How can I get the last record (max(created_at)
) of each equipment_id
?
I've tried both the following queries, with several variants that I've read through many answers of this topic:
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;
I have also tried creating btree indexes for equipment_id,created_at
but Postgres finds that using a seqscan is faster. Forcing enable_seqscan = off
is of no use either since reading the index is as slow as the seq scan, probably worse.
The query must run periodically returning always the last.
Using Postgres 9.3.
Explain/analyze (with 1.7 million records):
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
values inequipment_id
the expected percentage is below 0.1%