Mam bardzo proste zapytanie SQL:
SELECT COUNT(DISTINCT x) FROM table;
Moja tabela ma około 1,5 miliona wierszy. To zapytanie działa dość wolno; zajmuje to około 7,5 s, w porównaniu do
SELECT COUNT(x) FROM table;
co trwa około 435 ms. Czy istnieje sposób na zmianę zapytania w celu zwiększenia wydajności? Próbowałem grupować i regularnie liczyć, a także umieszczać indeks na x; oba mają ten sam czas wykonania 7,5 s.
performance
postgresql
count
distinct
ferson2020
źródło
źródło
\d
wynikpsql
jest dobry) i sprecyzować kolumnę, z którą masz problem. Dobrze byłoby zobaczyćEXPLAIN ANALYZE
oba zapytania.Odpowiedzi:
Możesz użyć tego:
Jest to znacznie szybsze niż:
źródło
COUNT(DISTINCT())
wykonuje sortowanie, z pewnością pomocne będzie posiadanie indeksu nacolumn_name
szczególnie przy stosunkowo niewielkiej ilościwork_mem
(gdzie haszowanie da stosunkowo dużą liczbę partii). Od tego czasu użycie COUNT (DISTINCT () _, prawda?Count(column)
liczy tylko wartości inne niż null.count(*)
liczy wiersze. Tak więc pierwszy / dłuższy zlicza również wiersz pusty (raz). Zmień na,count(column_name)
aby zachowywały się tak samo.Wyniki:
Ten sam plan, co w przypadku CTE, można by prawdopodobnie stworzyć innymi metodami (funkcje okna)
źródło
Jeśli twoja
count(distinct(x))
jest znacznie wolniejsza niżcount(x)
wtedy, możesz przyspieszyć to zapytanie, utrzymując liczniki wartości x w innej tabeli, na przykładtable_name_x_counts (x integer not null, x_count int not null)
używając wyzwalaczy. Jednak wydajność zapisu ucierpi i jeśli zaktualizujesz wielex
wartości w jednej transakcji, musisz to zrobić w jakiejś jawnej kolejności, aby uniknąć możliwego impasu.źródło
Szukałem również tej samej odpowiedzi, ponieważ w pewnym momencie potrzebowałem total_count z odrębnymi wartościami wraz z limitem / przesunięciem .
Ponieważ jest to trochę trudne, aby uzyskać całkowitą liczbę z różnymi wartościami wraz z limitem / przesunięciem. Zwykle trudno jest uzyskać całkowitą liczbę z limitem / przesunięciem. W końcu udało mi się zrobić -
SELECT DISTINCT COUNT(*) OVER() as total_count, * FROM table_name limit 2 offset 0;
Wydajność zapytań jest również wysoka.
źródło