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
SELECT
spisuj, 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
FILTR
klauzula w Postgresie 9.4 lub nowszym. Jest czystszy i trochę szybszy. Zobacz: