Tja, båda dina frågor finns i olika tabeller (reportimpression
kontra reportimpressionday
), så jämförelsen av de två frågorna är verkligen inte en jämförelse. Har du ANALYSERAR
både? Olika kolumnstatistik kan också spela en roll. Index eller tabelluppsvällning kan vara annorlunda. Kvalificerar en större del av alla rader till februari 2019? Etc.
Ett skott i mörkret, jämför procenttalen för båda tabellerna:
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;
Är den för reportimpression
större? Då kan det bara överstiga det antal som ett index förväntas hjälpa till.
I allmänhet är ditt index reportimpression_datelocal_index
on (datelocal) ser bra ut för det, och reportimpression_viewership_index
tillåter även index-endast skanningar om autovakuum slår skrivbelastningen på bordet. (Även om visningar
&åldersgrupp
är bara dödfrakt för detta och det skulle fungera ännu bättre utan).
Svar
Du fick 26,6 procent och dagen är 26,4 procent
för min fråga. För en så stor andel är index vanligtvis inte användbara överhuvudtaget . En sekventiell skanning är vanligtvis det snabbaste sättet. Endast index-skanningar kan fortfarande vettigt om den underliggande tabellen är mycket större. (Eller så har du svår tabelluppsvällning och mindre uppsvällda index, vilket gör index mer attraktiva igen.)
Din första fråga kanske bara ligger över vändpunkten. Försök att begränsa tidsramen tills du ser skanningar som endast är indexerade. Du kommer inte att se (bitmapps) indexsökningar med mer än ungefär 5 % av alla rader som är kvalificerade (beror på många faktorer).
Frågor
Hur som helst, överväg dessa modifierade frågor:
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;
Huvudpunkter
-
När du använder lokaliserat datumformat som
'2-1-2019'
, gå igenomto_timestamp()
med explicita formatspecifikationer. Annars beror detta på lokala inställningar och kan gå sönder (tyst) när det anropas från en session med andra inställningar. Använd hellre ISO-datum/tidsformat som visas som inte beror på lokalinställningar. -
Det verkar som att du vill inkludera hela månaden av februari. Men din fråga missar den övre gränsen. För det första kan februari ha 29 dagar. En
datelocal <'2-28-2019'
utesluter hela 28 februari också. Använddatelocal <'2019-03-01'
istället. -
Det är billigare att gruppera och sortera efter samma uttryck som du har i
SELECT
lista om du kan. Så använddate_trunc()
där med. Använd inte olika uttryck utan behov. Om du behöver datumdelen i resultatet, tillämpa den på det grupperade uttrycket, som:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Lite mer brusig kod, men snabbare (och möjligen lättare att optimera för frågeplaneraren också).
-
Använd samlade
FILTER
klausul i Postgres 9.4 eller senare. Det är renare och lite snabbare. Se: