Cóż, oba zapytania znajdują się w różnych tabelach (reportimpression a reportimpressionday ), więc porównanie dwóch zapytań tak naprawdę nie jest porównaniem. Czy Analiza? Zarówno? Pewną rolę mogą również odgrywać różne statystyki kolumnowe. Indeks lub rozdęcie tabeli mogą być inne. Czy większa część wszystkich wierszy kwalifikuje się do lutego 2019? Itd.
Jedno ujęcie w ciemności, porównaj wartości procentowe dla obu tabel:
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;
To ten dla reportimpression większy? Wtedy może po prostu przekroczyć liczbę, dla której indeks ma pomóc.
Ogólnie rzecz biorąc, Twój indeks reportimpression_datelocal_index on (datelocal) wygląda na to dobrze, a reportimpression_viewership_index pozwala nawet na skanowanie tylko indeksu, jeśli autovacuum pokona obciążenie zapisu na stole. (Chociaż wyświetlenia &grupa wiekowa to tylko martwy ładunek za to i bez niego działałoby jeszcze lepiej).
Odpowiedź
Masz 26,6 procent, a dzień to 26,4 procent dla mojego zapytania. W przypadku tak dużego odsetka indeksy zazwyczaj nie są przydatne w ogóle . Skanowanie sekwencyjne jest zazwyczaj najszybszym sposobem. Tylko skanowanie tylko do indeksu może nadal ma sens, jeśli tabela bazowa jest znacznie większa. (Lub masz poważne rozdęcie tabeli i mniej rozdęte indeksy, co sprawia, że indeksy znów są bardziej atrakcyjne.)
Twoje pierwsze zapytanie może dotyczyć właśnie punktu krytycznego. Spróbuj zawęzić przedział czasu, aż zobaczysz skany tylko z indeksem. Nie zobaczysz skanów indeksów (map bitowych), w których kwalifikuje się więcej niż około 5% wszystkich wierszy (w zależności od wielu czynników).
Zapytania
Tak czy inaczej, rozważ te zmodyfikowane zapytania:
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;
Główne punkty
-
W przypadku korzystania ze zlokalizowanego formatu daty jak
'2-1-2019', przejdź doto_timestamp()z jawnymi specyfikatorami formatu. W przeciwnym razie zależy to od ustawień regionalnych i może zostać przerwane (po cichu) po wywołaniu z sesji z innymi ustawieniami. Raczej używaj formatów daty / czasu ISO, jak pokazano, które nie zależą od ustawień regionalnych. -
Wygląda na to, że chcesz uwzględnić cały miesiąc lutowy. Ale twoje zapytanie nie mieści się w górnej granicy. Po pierwsze, luty może mieć 29 dni.
datelocal <'2-28-2019'wyklucza również wszystkie 28 lutego. Użyjdatelocal <'2019-03-01'zamiast tego. -
Taniej jest grupować i sortować według tego samego wyrażenia tak jak w
SELECTspisuj, jeśli możesz. Użyj więcdate_trunc()tam też. Nie używaj różnych wyrażeń bez potrzeby. Jeśli potrzebujesz część daty w wyniku, zastosuj ją do zgrupowanego wyrażenia, na przykład:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);Nieco bardziej hałaśliwy kod, ale szybszy (i prawdopodobnie łatwiejszy do optymalizacji również pod kątem planowania zapytań).
-
Użyj agregacji
FILTRklauzula w Postgresie 9.4 lub nowszym. Jest czystszy i trochę szybszy. Zobacz: