Nå, begge dine forespørgsler er på forskellige tabeller (reportimpression
vs. rapportindtryksdag
), så sammenligningen af de to forespørgsler er virkelig ikke en sammenligning. Har du ANALYSERET
begge? Forskellige kolonnestatistikker kan også spille en rolle. Indeks eller tabelbloat kan være anderledes. Er en større del af alle rækker kvalificeret til februar 2019? osv.
Et skud i mørket, sammenlign procenterne for begge tabeller:
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;
Er den til reportimpression
større? Så er det måske lige over det antal, som et indeks forventes at hjælpe for.
Generelt er dit indeks reportimpression_datelocal_index
on (datelocal) ser godt ud til det, og reportimpression_viewership_index
tillader endda kun indeksscanninger, hvis autovakuum slår skrivebelastningen på bordet. (Selvom visninger
&aldersgruppe
er bare dødfragt for dette, og det ville fungere endnu bedre uden).
Svar
Du fik 26,6 procent, og dagen er 26,4 procent
for min forespørgsel. For så stor en procentdel er indekser typisk ikke nyttige slet . En sekventiel scanning er typisk den hurtigste måde. Kun indeksscanninger må stadig giver mening, hvis den underliggende tabel er meget større. (Eller du har alvorlig tabel oppustethed og mindre oppustede indekser, hvilket gør indeks mere attraktive igen.)
Din første forespørgsel er måske lige på den anden side af vendepunktet. Prøv at indsnævre tidsrammen, indtil du ser kun indeksscanninger. Du vil ikke se (bitmap) indeksscanninger, hvor mere end ca. 5 % af alle rækker kvalificerer (afhænger af mange faktorer).
Forespørgsler
Uanset hvad, så overvej disse modificerede forespørgsler:
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;
Vigtige punkter
-
Når du bruger lokaliseret datoformat som
'2-1-2019'
, gå gennemto_timestamp()
med eksplicitte formatspecifikationer. Ellers afhænger dette af lokalitetsindstillinger og kan gå i stykker (stille), når det kaldes fra en session med andre indstillinger. Brug hellere ISO-dato/tidsformater som vist, som ikke afhænger af lokalitetsindstillinger. -
Det ser ud til, at du vil inkludere hele måneden af februar. Men din forespørgsel går glip af den øvre grænse. For det første kan februar have 29 dage. En
datelocal <'2-28-2019'
udelukker også hele 28. februar. Brugdatelocal <'2019-03-01'
i stedet. -
Det er billigere at gruppere og sortere efter det samme udtryk som du har i
SELECT
liste, hvis du kan. Så brugdate_trunc()
også der. Brug ikke forskellige udtryk uden behov. Hvis du bruger datodelen i resultatet, anvende den på det grupperede udtryk, som:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Lidt mere støjende kode, men hurtigere (og muligvis også nemmere at optimere til forespørgselsplanlæggeren).
-
Brug det samlede
FILTER
klausul i Postgres 9.4 eller nyere. Det er renere og lidt hurtigere. Se: