Aby obliczyć procent, muszę znać liczbę wierszy w tabeli. Jeśli całkowita liczba jest większa niż pewna predefiniowana stała, użyję stałej wartości. W przeciwnym razie użyję rzeczywistej liczby wierszy.
Mogę użyć SELECT count(*) FROM table
. Ale jeśli moja stała wartość to 500 000, a w tabeli mam 5 000 000 000 wierszy, liczenie wszystkich wierszy spowoduje stratę czasu.
Czy można przerwać liczenie, gdy tylko moja stała wartość zostanie przekroczona?
Potrzebuję dokładnej liczby wierszy tylko wtedy, gdy jest poniżej podanego limitu. W przeciwnym razie, jeśli liczba jest powyżej limitu, zamiast tego używam wartości granicznej i chcę odpowiedzi jak najszybciej.
Coś takiego:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
sql
postgresql
count
row
Renato Dinhani
źródło
źródło
Odpowiedzi:
Zliczanie wierszy w dużych tabelach jest znane w PostgreSQL jako powolne. Aby uzyskać dokładną liczbę, musi wykonać pełne zliczenie wierszy ze względu na charakter MVCC . Istnieje sposób, aby radykalnie to przyspieszyć, jeśli liczba nie musi być dokładna, jak się wydaje w twoim przypadku.
Zamiast uzyskiwać dokładną liczbę ( powolne przy dużych stołach):
Otrzymujesz przybliżone oszacowanie w ten sposób ( niezwykle szybko ):
To, jak dokładne jest oszacowanie, zależy od tego, czy biegasz
ANALYZE
wystarczająco. Zwykle jest bardzo blisko.Zobacz FAQ Wiki PostgreSQL .
Lub dedykowana strona wiki dla wydajności count (*) .
Jeszcze lepiej
W artykule w PostgreSQL Wiki
jestbył nieco niechlujny . Zignorował możliwość, że może istnieć wiele tabel o tej samej nazwie w jednej bazie danych - w różnych schematach. Aby to uwzględnić:Albo jeszcze lepiej
Szybszy, prostszy, bezpieczniejszy, bardziej elegancki. Zobacz podręcznik dotyczący typów identyfikatorów obiektów .
Użyj
to_regclass('myschema.mytable')
w Postgres 9.4+, aby uniknąć wyjątków dla nieprawidłowych nazw tabel:TABLESAMPLE SYSTEM (n)
w Postgres 9.5+Podobnie jak w komentarzu @a_horse , nowo dodana klauzula
SELECT
polecenia może być przydatna, jeśli statystyki w programiepg_class
nie są z jakiegoś powodu wystarczająco aktualne. Na przykład:autovacuum
biegania.INSERT
lubDELETE
.TEMPORARY
stoły (które nie są objęteautovacuum
).To patrzy tylko na losowy n % (
1
w przykładzie) wybór bloków i liczy wiersze w nim. Większa próbka zwiększa koszt i zmniejsza błąd, Twój wybór. Dokładność zależy od wielu czynników:FILLFACTOR
zajmują miejsce na blok. Jeśli rozkład jest nierównomierny w tabeli, oszacowanie może być nieprawidłowe.W większości przypadków oszacowanie z
pg_class
będzie szybsze i dokładniejsze.Odpowiedz na aktualne pytanie
I czy to ...
Tak. Możesz użyć podzapytania z
LIMIT
:Postgres faktycznie przestaje liczyć poza podany limit, otrzymasz dokładną i aktualną liczbę dla maksymalnie n wierszy (w przykładzie 500000) i n w przeciwnym razie.
pg_class
Jednak nie tak szybko, jak szacowano .źródło
tablesample
klauzuli: np.select count(*) * 100 as cnt from mytable tablesample system (1);
SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;
(Pytam, ponieważ próbuję uzyskać liczbę z dowolnego zapytania, które może już zawierać klauzulę limitu)ORDER BY something
gdy nie może używać indeksu lub funkcji agregujących). Poza tym przetwarzana jest tylko ograniczona liczba wierszy z podzapytania.Zrobiłem to raz w aplikacji postgres, uruchamiając:
Następnie zbadaj dane wyjściowe za pomocą wyrażenia regularnego lub podobnej logiki. W przypadku prostego polecenia SELECT * pierwsza linia wyniku powinna wyglądać mniej więcej tak:
Możesz użyć tej
rows=(\d+)
wartości jako przybliżonego oszacowania liczby wierszy, które zostaną zwrócone, a następnie wykonaj rzeczywistą wartość tylkoSELECT COUNT(*)
wtedy, gdy oszacowanie jest, powiedzmy, mniejsze niż 1,5-krotność progu (lub dowolnej liczby, którą uznasz za sensowną dla Twojej aplikacji).W zależności od złożoności zapytania liczba ta może być coraz mniej dokładna. W rzeczywistości w mojej aplikacji, gdy dodaliśmy łączenia i złożone warunki, stało się to tak niedokładne, że było całkowicie bezwartościowe, nawet wiedzieć, jak w ramach potęgi 100, ile wierszy byśmy zwrócili, więc musieliśmy porzucić tę strategię.
Ale jeśli zapytanie jest na tyle proste, że Pg może przewidzieć, z pewnym rozsądnym marginesem błędu, ile wierszy zwróci, może to zadziałać.
źródło
Odniesienie zaczerpnięte z tego bloga.
Możesz użyć poniżej, aby wyszukać liczbę wierszy.
Korzystanie z pg_class:
Korzystanie z pg_stat_user_tables:
źródło
W Oracle można użyć
rownum
do ograniczenia liczby zwracanych wierszy. Domyślam się, że podobna konstrukcja istnieje również w innych SQL. Tak więc w podanym przykładzie możesz ograniczyć liczbę zwracanych wierszy do 500001 i zastosować acount(*)
następnie:źródło
count(*)
z rownum, 1 s bez użycia rownum). Tak,SELECT count(*) cnt FROM table
zawsze zwraca 1 wiersz, ale z warunkiem LIMIT zwraca „500001”, gdy rozmiar tabeli przekracza 500000 i <size>, gdy rozmiar tabeli wynosi <= 500000.Jak szeroka jest kolumna tekstu?
Z GROUP BY niewiele można zrobić, aby uniknąć skanowania danych (przynajmniej skanowania indeksu).
Polecam:
Jeśli to możliwe, zmiana schematu w celu usunięcia duplikatów danych tekstowych. W ten sposób zliczanie będzie się odbywać na wąskim polu klucza obcego w tabeli „wiele”.
Możesz też utworzyć wygenerowaną kolumnę z HASH tekstu, a następnie GROUP BY kolumnę z krzyżykiem. Ponownie, ma to na celu zmniejszenie obciążenia pracą (przejrzyj indeks wąskiej kolumny)
Edytować:
Twoje pierwotne pytanie nie do końca pasowało do Twojej zmiany. Nie jestem pewien, czy wiesz, że funkcja COUNT, gdy jest używana z funkcją GROUP BY, zwróci liczbę elementów na grupę, a nie liczbę elementów w całej tabeli.
źródło
Możesz uzyskać liczbę za pomocą poniższego zapytania (bez * lub jakichkolwiek nazw kolumn).
źródło
count(*)
.W przypadku SQL Server (2005 lub nowszy) szybką i niezawodną metodą jest:
Szczegóły dotyczące sys.dm_db_partition_stats są wyjaśnione w witrynie MSDN
Zapytanie dodaje wiersze ze wszystkich części (prawdopodobnie) podzielonej na partycje tabeli.
index_id = 0 to nieuporządkowana tabela (Heap), a index_id = 1 to uporządkowana tabela (indeks klastrowy)
Jeszcze szybsze (ale zawodne) metody są szczegółowo opisane tutaj.
źródło