Prawdopodobnie nie chcesz tego słyszeć, ale najlepszym sposobem na przyspieszenie SELECT DISTINCT
jest unikanie go DISTINCT
tego. W wielu przypadkach (nie wszystkie!) Można tego uniknąć dzięki lepszemu projektowaniu bazy danych lub lepszym zapytaniom.
Czasami GROUP BY
jest szybszy, ponieważ wymaga innej ścieżki kodu.
W twoim szczególnym przypadku nie wydaje się, że możesz się go pozbyć DISTINCT
. Ale możesz obsługiwać zapytanie za pomocą specjalistycznego indeksu, jeśli masz wiele tego rodzaju zapytań:
CREATE INDEX foo ON events (project_id, "time", user_id);
Dodawanie user_id
jest przydatne tylko wtedy, gdy otrzymujesz z tego skany tylko indeksowe . Kliknij link, aby uzyskać szczegółowe informacje. Usunąłby kosztowny skan stosów bitmap ze swojego planu zapytań, który zajmuje 90% czasu zapytania.
Twój EXPLAIN
wynik mówi mi, że zapytanie musi skondensować 2491 różnych użytkowników z pół miliona pasujących wierszy. Nie stanie się to superszybkie, bez względu na to, co robisz, ale może być znacznie szybsze.
Jeśli przedziały czasowe w twoich zapytaniach są zawsze takie same, MATERIALIIZED VIEW
składanie user_id
na per (project_id, <fixed time intervall>)
byłoby daleko. Nie ma tam jednak szansy w różnych odstępach czasu. Może mógłbyś co najmniej spasować użytkowników na godzinę lub inną minimalną jednostkę czasu, a to zapewniłoby wystarczającą wydajność, aby zagwarantować znaczne obciążenie.
Nitpick:
Najprawdopodobniej prognozy "time"
powinny być naprawdę:
AND "time" >= '2015-01-11 8:00:00'
AND "time" < '2015-02-10 8:00:00';
Poza:
nie używaj time
jako identyfikatora. To słowo zastrzeżone w standardowym języku SQL i podstawowy typ w Postgres.
Oto mój test w sprawie Sama i odpowiedź Erwina
Erwin powiedział: „Prawdopodobnie nie chcesz tego słyszeć, ale najlepszą opcją na przyspieszenie SELECT DISTINCT jest unikanie DISTINCT na początek. W wielu przypadkach (nie wszystkie!) Można tego uniknąć dzięki lepszemu projektowaniu bazy danych lub lepszym zapytaniom „. Myślę, że ma rację, powinniśmy unikać używania „wyraźnego, grupowania według, sortowania według” (jeśli w ogóle).
Spotkałem sytuację jak w przypadku Sama i myślę, że Sam może użyć partycji na tabeli zdarzeń według miesiąca. Zmniejszy rozmiar danych podczas zapytania, ale potrzebujesz funkcji (pl / pgsql) do wykonania zamiast zapytania powyżej. Funkcja znajdzie odpowiednie partycje (w zależności od warunków) do wykonania zapytania.
źródło