Usando o PostgreSQL 9.2, tenho problemas com consultas lentas em uma tabela relativamente grande (mais de 200 milhões de linhas). Não estou tentando nada louco, apenas adicionando valores históricos. Abaixo está a consulta e a saída do plano de consulta.
Meu layout de tabela:
Table "public.energy_energyentry"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('energy_energyentry_id_seq'::regclass)
prop_id | integer | not null
timestamp | timestamp with time zone | not null
value | double precision | not null
Indexes:
"energy_energyentry_pkey" PRIMARY KEY, btree (id)
"energy_energyentry_prop_id" btree (prop_id)
"energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
"energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED
Os dados variam de 01-01-2012 até agora, com novos dados sendo constantemente adicionados. Existem cerca de 2,2 mil valores distintos na prop_id
chave estrangeira, distribuídos uniformemente.
Percebo que as estimativas de linha não estão muito longe, mas as estimativas de custo parecem maiores pelo fator 4x. Provavelmente isso não é um problema, mas há algo que eu possa fazer sobre isso?
Espero que o acesso ao disco seja o problema, pois a tabela não fica na memória o tempo todo.
EXPLAIN ANALYZE
SELECT SUM("value")
FROM "energy_energyentry"
WHERE
"prop_id"=82411
AND "timestamp">'2014-06-11'
AND "timestamp"<'2014-11-11'
;
Aggregate (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1) -> Index Scan using energy_energyentry_prop_id_timestamp_idx on energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1) Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone)) Total runtime: 51504.841 ms
Alguma sugestão de como tornar isso mais rápido?
Também estou bem em ouvir que não fiz nada de estranho.
prop_time_idx
, mas a definição da tabela mostraentry_prop_id_timestamp_idx
. Este é o mesmo índice? Por favor conserte.prop
)? Se apenas uma pequena porcentagem, talvez um índice("timestamp", prop)
fosse melhor. Vários índices com as mesmas colunas iniciais (prop
no seu caso) também costumam ser redundantes.Respostas:
Sua tabela é grande , assim como qualquer índice que abranja toda a tabela. Assumindo que:
timestamp = now()
) são inseridosEu sugeriria um índice parcial, com várias colunas (cobertura!) :
Inclua apenas o período consultado regularmente. A eficácia se deteriora com o tempo com novas entradas. Recrie o índice de tempos em tempos. (Talvez você precise adaptar suas consultas.) Consulte a resposta vinculada abaixo.
O valor da última coluna é incluído apenas para obter verificações somente de índice . A configuração agressiva de autovacuum pode ajudar, mantendo o mapa de visibilidade atualizado, como @jjanes já mencionado .
O índice parcial deve caber na RAM mais facilmente e permanecer por mais tempo.
Pode ser necessário incluir essa
WHERE
condição nas consultas para fazer o planejador entender que o índice é aplicável à consulta, como:Como sua consulta está somando muitas linhas (
rows=13578
), isso levará algum tempo, mesmo com uma verificação apenas de índice. No entanto, não deve demorar nem 50 segundos. Menos de um segundo em qualquer hardware decente.Relacionados (mas ignore
CLUSTER
eFILLFACTOR
, ambos são irrelevantes se você puder obter verificações somente de índice) :Além disso:
como atualmente você tem um índice
(prop_id, "timestamp")
, o índice adicional(prop_id)
pode custar mais do que vale:fonte
Se você ativar o índice (prop_id, "timestamp", "value"), poderá usar uma varredura apenas do índice para calcular o valor sem nunca visitar a tabela. Isso pode economizar muito acesso aleatório ao disco.
Para obter o máximo benefício, você precisa ser agressivo ao aspirar a mesa. As configurações padrão do autovac não são agressivas o suficiente para tabelas somente de inserção nas quais você deseja suportar com eficiência as verificações apenas de índice.
fonte