sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan får man date_part-forespørgsel til at ramme indeks?

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 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å gennem to_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. Brug datelocal <'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å brug date_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:




  1. PostgreSQL Upsert (On Conflict) med samme værdier i Insert og Update

  2. Undtagelseshåndtering i Procedure med indlejrede funktioner i pl/sql

  3. Ny bruger og LDAP-styring i ClusterControl 1.8.2

  4. Tjek begrænsning i SQL