Dada a tabela:
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)
A tabela possui 20 milhões de registros que não são, relativamente falando, um grande número. Mas torna as verificações sequenciais lentas.
Como posso obter o último registro ( max(created_at)
) de cada um equipment_id
?
Eu tentei as duas consultas a seguir, com várias variantes que li através de muitas respostas deste tópico:
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;
Eu também tentei criar índices btree para, equipment_id,created_at
mas o Postgres acha que usar um seqscan é mais rápido. Forçar enable_seqscan = off
também não serve, pois a leitura do índice é tão lenta quanto a verificação seq, provavelmente pior.
A consulta deve ser executada periodicamente, retornando sempre a última.
Usando o Postgres 9.3.
Explique / analise (com 1,7 milhão de registros):
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
valores emequipment_id
percentagem espera-se abaixo de 0,1%Respostas:
Um índice simples de várias colunas b-tree deve funcionar:
Por que
DESC NULLS LAST
?Função
Se você não conseguir entender o sentido do planejador de consultas, uma função que percorre a tabela de equipamentos deve fazer o truque. A procura de um equipment_id de cada vez usa o índice. Para um número pequeno (57 a julgar pela sua
EXPLAIN ANALYZE
saída), isso é rápido.É seguro assumir que você tem uma
equipment
mesa?Também faz uma boa ligação:
Subconsultas correlacionadas
Venha para pensar sobre isso, usando esta
equipment
tabela, você pode trabalhar sujo com subconsultas pouco correlacionadas com grande efeito:O desempenho é muito bom.
LATERAL
junte-se ao Postgres 9.3+Explicação detalhada:
Desempenho semelhante ao da subconsulta correlacionada. Comparando o desempenho de
max()
,DISTINCT ON
, função, correlacionado subconsulta eLATERAL
nisto:SQL Fiddle .
fonte
Tentativa 1
E se
equipment
mesa separada egeoposition_records(equipment_id, created_at desc)
então o seguinte funciona para mim:
Eu não era capaz de forçar PG para fazer uma consulta rápida para determinar tanto a lista de
equipment_id
s eo relacionadomax(created_at)
. Mas vou tentar novamente amanhã!Tentativa 2
Encontrei este link: http://zogovic.com/post/44856908222/optimizing-postgresql-query-for-distinct-values Combinando essa técnica com a minha consulta da tentativa 1, recebo:
e isso funciona RÁPIDO! Mas você precisa
geoposition_records(equipment_id, created_at desc)
.fonte