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 durchto_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 Siedatelocal < '2019-03-01'
stattdessen. -
Es ist billiger, nach demselben Ausdruck zu gruppieren und zu sortieren wie im
SELECT
Liste wenn du kannst. Verwenden Sie alsodate_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: