Eu tenho uma tabela com vários terabytes de dados de eventos em um esquema muito simples (id, bucket_id, data,created_at) e há um índice como este
create index index_events_on_created_at_and_bucket_id
on public.events (created_at desc, bucket_id asc);
Agora pensei que seria rápido encontrar o ID do evento mais recente em cada bucket com uma consulta como:
select max(created_at), bucket_id from events group by bucket_id;
Explique a saída:
HashAggregate (cost=170172168.62..170172178.41 rows=979 width=16)
Group Key: bucket_id
-> Index Only Scan using index_events_on_created_at_and_bucket_id on events (cost=0.70..156003994.34 rows=2833634856 width=16)
Parece estar usando o índice, mas fazendo uma varredura do índice em vez de apenas capturar o valor principal como eu esperava. De qualquer forma, ele não é concluído em tempo hábil. Suponho que seja um problema ao usar a função agregada na consulta, mas não sei como consertar.
Existe uma consulta que pode retornar o carimbo de data/hora mais recente (ou seja, o primeiro no índice) created_at
de cada intervalo, obtendo-o desse índice?
Melhor índice com liderança
bucket_id
Você quer uma linha por balde. Um índice com início
bucket_id
será muito mais útil.Relacionado:
Como você tem um número muito pequeno de valores distintos em
bucket_id
( "rows=979" ), esta técnica de consulta deve fornecer resultados muito mais rápidos, com base no meu índice sugerido:Ele emula uma "varredura de índice solto", escolhendo apenas a "primeira" linha para cada distinto
bucket_id
- exatamente o que você está procurando.Observe como a ordem de classificação na consulta corresponde meticulosamente ao índice.
Se o mapa de visibilidade da tabela estiver atualizado (ou seja, a tabela estiver limpa o suficiente), você obterá varreduras apenas de índice. Deve ser aplicado, já que a consulta lenta que você demonstrou também obteve uma verificação somente de índice. (Embora isso seja uma varredura de todo o índice, em vez de apenas as entradas principais por intervalo). Relacionado:
Isso pressupõe que ambas as colunas de interesse sejam
NOT NULL
. Caso contrário, você terá que fazer mais.Se você também tiver uma tabela
bucket
com uma linha por relevantebucket_id
, isso será ainda um pouco mais rápido:Ver:
Preso com índice ativado
(created_at DESC, bucket_id ASC)
Podemos trabalhar com as metainformações adicionais dos seus comentários:
Você pode aprimorar as consultas acima, mas um ângulo diferente com base nisso deve ter um desempenho melhor:
Deve ser mais rápido quando limitado à pequena (?) fração das linhas mais recentes. O Postgres pode ler as linhas superiores do índice e alimentá-las
DISTINCT ON
. SobreDISTINCT ON
: