Prawdopodobnie nie chcesz tego słyszeć, ale najlepszym sposobem na przyspieszenie SELECT DISTINCTjest unikanie go DISTINCT tego. W wielu przypadkach (nie wszystkie!) Można tego uniknąć dzięki lepszemu projektowaniu bazy danych lub lepszym zapytaniom.
Czasami GROUP BYjest 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_idjest 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 VIEWskładanie user_idna 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 timejako identyfikatora. To słowo zastrzeżone w standardowym języku SQL i podstawowy typ w Postgres.