sql >> Database >  >> RDS >> PostgreSQL

Hoe de date_part-query te krijgen om de index te raken?

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 door to_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. Gebruik datelocal < '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 dus date_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:




  1. SQL Server 2016:een login aanmaken

  2. Oracle PL/SQL - Verhoog de door de gebruiker gedefinieerde uitzondering met aangepaste SQLERRM

  3. Fout (Mac OS):sudo pip install MySQl-python

  4. JDBC voert de opdracht SHOW DATABASES niet uit