Welnu, uw beide zoekopdrachten bevinden zich op verschillende tabellen (reportimpression
vs. reportimpressionday
), dus de vergelijking van de twee zoekopdrachten is niet echt een vergelijking. Heb je ANALYZE
beide? Ook kunnen verschillende kolomstatistieken een rol spelen. Index of tafelzwelling kan anders zijn. Komt een groter deel van alle rijen in aanmerking voor februari 2019? enz.
One shot in the dark, vergelijk de percentages voor beide tabellen:
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;
Is die voor reportimpression
groter? Dan kan het net het aantal overschrijden waarvoor een index naar verwachting zal helpen.
Over het algemeen is uw index reportimpression_datelocal_index
op (datelocal) ziet er goed uit, en reportimpression_viewership_index
maakt zelfs scans met alleen index mogelijk als autovacuum de schrijfbelasting op de tafel verslaat. (Hoewel impressions
&agegroup
zijn hiervoor gewoon dode vracht en het zou nog beter werken zonder).
Antwoord
Je hebt 26.6 percent, and day is 26.4 percent
voor mijn vraag. Voor zo'n groot percentage zijn indexen helemaal niet nuttig . Een sequentiële scan is meestal de snelste manier. Alleen indexscans mag nog steeds logisch als de onderliggende tabel veel groter is. (Of je hebt ernstig opgeblazen tafel en minder opgeblazen indexen, waardoor indexen weer aantrekkelijker worden.)
Uw eerste zoekopdracht bevindt zich misschien net over het kantelpunt. Probeer het tijdsbestek te verkleinen totdat u alleen-index scans ziet. U zult geen (bitmap) indexscans zien waarbij meer dan ongeveer 5% van alle rijen in aanmerking komt (afhankelijk van veel factoren).
Vragen
Hoe het ook zij, overweeg deze aangepaste zoekopdrachten:
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;
Belangrijkste punten
-
Bij gebruik van gelokaliseerde datumnotatie zoals
'2-1-2019'
, ga doorto_timestamp()
met expliciete formaatspecificaties. Anders hangt dit af van de landinstellingen en kan het (stil) kapot gaan als er wordt gebeld vanuit een sessie met andere instellingen. Gebruik liever ISO-datum-/tijdnotaties zoals aangetoond die niet afhankelijk zijn van landinstellingen. -
Het lijkt erop dat u de hele maand . wilt opnemen van februari. Maar uw zoekopdracht mist de bovengrens. Ten eerste kan februari 29 dagen hebben. Een
datelocal < '2-28-2019'
sluit ook heel 28 februari uit. Gebruikdatelocal < '2019-03-01'
in plaats daarvan. -
Het is goedkoper om groeperen en sorteren op dezelfde uitdrukking zoals je hebt in de
SELECT
lijst als je kunt. Gebruik dusdate_trunc()
daar ook. Gebruik geen verschillende uitdrukkingen zonder noodzaak. Als je nodig het datepart in het resultaat, pas het toe op de gegroepeerde uitdrukking, zoals:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Een beetje luidruchtigere code, maar sneller (en mogelijk ook gemakkelijker te optimaliseren voor de queryplanner).
-
Gebruik het geaggregeerde
FILTER
clausule in Postgres 9.4 of hoger. Het is schoner en een beetje sneller. Zie: