PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie bekomme ich die date_part-Abfrage, um den Index zu treffen?

Nun, Ihre beiden Abfragen befinden sich in verschiedenen Tabellen (reportimpression vs. reportimpressionday ), also ist der Vergleich der beiden Abfragen wirklich kein Vergleich. Haben Sie ANALYZE? beide? Verschiedene Spaltenstatistiken können ebenfalls eine Rolle spielen. Das Aufblähen von Index oder Tabelle kann unterschiedlich sein. Qualifiziert sich ein größerer Teil aller Zeilen für Februar 2019? usw.

Ein Schuss im Dunkeln, vergleichen Sie die Prozentsätze für 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;

Ist derjenige für reportimpression größer? Dann könnte es die Zahl überschreiten, für die ein Index helfen soll.

Im Allgemeinen Ihr Index reportimpression_datelocal_index on (datelocal) sieht gut aus und reportimpression_viewership_index erlaubt sogar Nur-Index-Scans, wenn Autovacuum die Schreiblast auf der Tabelle übertrifft. (Obwohl impressions &agegroup sind dafür nur tote Fracht und ohne würde es noch besser gehen).

Antwort

Sie haben 26.6 percent, and day is 26.4 percent für meine frage. Für einen so großen Prozentsatz sind Indizes normalerweise überhaupt nicht nützlich . Ein sequenzieller Scan ist normalerweise der schnellste Weg. Nur Index-Only-Scans darf immer noch sinnvoll, wenn die zugrunde liegende Tabelle viel größer ist. (Oder Sie haben schwere Tabellenaufblähung und weniger aufgeblähte Indizes, was Indizes wieder attraktiver macht.)

Ihre erste Abfrage könnte gerade den Wendepunkt überschritten haben. Versuchen Sie, den Zeitrahmen einzuschränken, bis Sie Nur-Index-Scans sehen. Sie werden keine (Bitmap-)Index-Scans sehen, bei denen mehr als ungefähr 5 % aller Zeilen qualifiziert sind (hängt von vielen Faktoren ab).

Abfragen

Beachten Sie jedoch diese modifizierten Abfragen:

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;

Wichtige Punkte

  • Bei Verwendung des lokalisierten Datumsformats wie '2-1-2019' , gehen Sie durch to_timestamp() mit expliziten Formatbezeichnern. Andernfalls hängt dies von den Gebietsschemaeinstellungen ab und kann (stillschweigend) abbrechen, wenn es von einer Sitzung mit anderen Einstellungen aufgerufen wird. Verwenden Sie lieber ISO-Datums-/Zeitformate wie demonstriert, die nicht von den Gebietsschema-Einstellungen abhängen.

  • Anscheinend möchten Sie den ganzen Monat einbeziehen von Februar. Aber Ihre Abfrage verfehlt die obere Grenze. Zum einen kann der Februar 29 Tage haben. Ein datelocal < '2-28-2019' schließt auch den gesamten 28. Februar aus. Verwenden Sie datelocal < '2019-03-01' stattdessen.

  • Es ist billiger, nach demselben Ausdruck zu gruppieren und zu sortieren wie im SELECT Liste wenn du kannst. Verwenden Sie also date_trunc() da auch. Verwenden Sie nicht ohne Notwendigkeit unterschiedliche Ausdrücke. Wenn Sie brauchen den Datumsteil im Ergebnis, wenden Sie ihn auf den gruppierten Ausdruck an, wie:

    SELECT date_part('day', date_trunc('day', datelocal)) AS day
    ...
    GROUP  BY date_trunc('day', datelocal)
    ORDER  BY date_trunc('day', datelocal);
    

    Etwas lauterer Code, aber schneller (und möglicherweise auch einfacher für den Abfrageplaner zu optimieren).

  • Verwenden Sie den aggregierten FILTER Klausel in Postgres 9.4 oder höher. Es ist sauberer und etwas schneller. Siehe: