Bem, ambas as suas consultas estão em tabelas diferentes (
reportimpression
vs. reportimpressionday
), então a comparação das duas consultas realmente não é uma comparação. Você ANALISE
Ambas? Várias estatísticas de coluna também podem desempenhar um papel. O inchaço do índice ou da tabela pode ser diferente. Uma parte maior de todas as linhas se qualifica para fevereiro de 2019? etc. Um tiro no escuro, compare as porcentagens para ambas as tabelas:
SELECT tbl, round(share * 100 / total, 2) As percentage
FROM (
SELECT text 'reportimpression' AS tbl
, count(*)::numeric AS total
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')::numeric AS share
FROM reportimpression
UNION ALL
SELECT 'reportimpressionday'
, count(*)
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')
FROM reportimpressionday
) sub;
É aquele para
reportimpression
Maior? Em seguida, pode exceder o número para o qual se espera que um índice ajude. Geralmente, seu índice
reportimpression_datelocal_index
on (datelocal) parece bom para ele, e reportimpression_viewership_index
até permite varreduras somente de índice se o autovacuum superar a carga de gravação na mesa. (Embora impressões
&grupo etário
são apenas frete morto para isso e funcionaria ainda melhor sem). Resposta
Você tem
26,6% e dia é 26,4%
para minha consulta. Para uma porcentagem tão grande, os índices normalmente não são úteis de forma alguma . Uma varredura sequencial geralmente é a maneira mais rápida. Somente verificações somente de índice podem ainda faz sentido se a tabela subjacente for muito maior. (Ou você tem grave tabela inchada e índices menos inchados, o que torna os índices mais atraentes novamente.) Sua primeira consulta pode ser apenas do outro lado do ponto de inflexão. Tente restringir o período de tempo até ver verificações somente de índice. Você não verá varreduras de índice (bitmap) com mais de 5% de todas as linhas qualificadas (dependendo de muitos fatores).
Consultas
Seja como for, considere estas consultas modificadas:
SELECT date_part('hour', datelocal) AS hour
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpression
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01' -- '2019-02-28' -- ?
GROUP BY 1
ORDER BY 1;
SELECT date_trunc('day', datelocal) AS day
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpressionday
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01'
GROUP BY 1
ORDER BY 1;
Pontos principais
-
Ao usar o formato de data localizado como'2-1-2019'
, acesseto_timestamp()
com especificadores de formato explícitos. Caso contrário, isso depende das configurações de localidade e pode ser interrompido (silenciosamente) quando chamado de uma sessão com configurações diferentes. Em vez disso, use os formatos de data/hora ISO, conforme demonstrado, que não dependem das configurações de localidade.
-
Parece que você deseja incluir o mês inteiro de fevereiro. Mas sua consulta perde o limite superior. Por um lado, fevereiro pode ter 29 dias. Umdatelocal <'2-28-2019'
exclui todo o dia 28 de fevereiro também. Usedatelocal <'2019-03-01'
em vez de.
-
É mais barato agrupar e classificar pela mesma expressão como você tem noSELECT
lista se puder. Então usedate_trunc()
ali também. Não use expressões diferentes sem necessidade. Se você precisar o datepart no resultado, aplique-o na expressão agrupada, como:
SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Um código um pouco mais barulhento, mas mais rápido (e possivelmente mais fácil de otimizar também para o planejador de consultas).
-
Use o agregadoFILTER
cláusula no Postgres 9.4 ou posterior. É mais limpo e um pouco mais rápido. Ver: