Tenho uma consulta que seleciona valores distintos de uma tabela e notei que o tempo de execução diminuiu significativamente após a execução inicial.
Aqui está a consulta e o plano de execução correspondente que obtive quando executei a consulta pela segunda vez.
EXPLAIN ANALYZE SELECT DISTINCT integration_type FROM my_schema.my_table;
Unique (cost=0.43..576843.69 rows=7 width=2) (actual time=0.032..2826.863 rows=8 loops=1)
-> Index Only Scan using my_index on my_schema.my_table (cost=0.43..538707.38 rows=15254521 width=2) (actual time=0.031..1881.219 rows=14730886 loops=1)
Heap Fetches: 1381786
Planning Time: 0.557 ms
Execution Time: 2826.897 ms
Pela primeira vez executei a consulta, demorou mais de 30 segundos. No entanto, as execuções sucessivas demoraram consistentemente menos de 3 segundos, embora o número de buscas de heap permanecesse o mesmo e não mudasse (ainda 1.381.786).
Estou curioso para entender por que o tempo de execução diminuiu para execuções sucessivas, apesar das buscas de heap inalteradas. Isso poderia estar relacionado a mecanismos de cache ou outras otimizações que o PostgreSQL emprega?
Estou usando o PostgreSQL versão 14.9
Quaisquer insights ou sugestões sobre por que esse comportamento ocorre e como posso otimizar ainda mais a consulta ou as configurações do banco de dados serão muito apreciados.
Obrigado.
As buscas de heap descrevem com que frequência uma varredura somente de índice precisava consultar a tabela para verificar a visibilidade. Ele não descreve com que frequência era necessário buscar dados do disco em vez da memória. Você não esperaria que o número necessário de buscas de heap mudasse à medida que os dados se tornassem residentes na memória. Ele ainda precisa consultar essas páginas, estejam elas na memória ou não.
Para determinar leituras de buffer, você precisa fazer isso
EXPLAIN (ANALYZE, BUFFERS)
e obter uma linha como:que informa quantos buffers consultados já estavam no pool shared_buffers.
Mas isso ainda não informa se as leituras do buffer foram falhas reais (e precisavam ser lidas no disco) ou se foram encontradas no cache de arquivos do sistema operacional. Portanto, você também deve ativar track_io_timing para obter não apenas uma contagem, mas também os tempos.
Livrar-se das buscas de heap precisa de um VÁCUO. Uma busca de heap que não existe não pode precisar atingir o disco. Aquele que existe pode ou não ser satisfeito pela memória, dependendo de quanta memória você tem e de quantas outras atividades estão acontecendo.