sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur får man date_part-frågan att träffa index?

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å igenom to_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änd datelocal <'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änd date_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:




  1. kombinera två välj uttalande i två kolumner?

  2. Oracle CLOB kan inte infoga mer än 4000 tecken?

  3. grails/mysql tidszon ändras

  4. ta bort dubbletter av rader från Oracle