Wiadomo, że w PostgreSQL zliczanie wierszy w dużych tabelach jest powolne. Model MVCC wymaga pełnej liczby aktywnych wierszy w celu uzyskania dokładnej liczby. Istnieją obejścia, które mogą znacznie przyspieszyć to jeśli liczba nie muszą być dokładne tak jak wydaje się być w twoim przypadku.
(Pamiętaj, że nawet „dokładna” liczba jest potencjalnie martwa w momencie przybycia!)
Dokładna liczba
Powoli dla dużych tabel.
W przypadku współbieżnych operacji zapisu może być nieaktualny w momencie, gdy go otrzymasz.
SELECT count(*) AS exact_count FROM myschema.mytable;
Oszacowanie
Niezwykle szybki :
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
Zazwyczaj oszacowanie jest bardzo zbliżone. Jak blisko, zależy od tego, czy ANALYZE lub VACUUM są wystarczająco uruchomione - gdzie "wystarczająco" jest określone przez poziom aktywności zapisu do twojego stołu.
Bezpieczniejsze oszacowanie
Powyższe pomija możliwość istnienia wielu tabel o tej samej nazwie w jednej bazie danych - w różnych schematach. Aby to uwzględnić:
SELECT c.reltuples::bigint AS estimate
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'mytable'
AND n.nspname = 'myschema';
Rzut na bigint formatuje real liczba ładnie, szczególnie dla dużych liczb.
Lepsze oszacowanie
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
Szybciej, prościej, bezpieczniej, bardziej elegancko. Zobacz podręcznik na temat typów identyfikatorów obiektów.
Zastąp 'myschema.mytable'::regclass z to_regclass('myschema.mytable') w Postgresie 9.4+, aby otrzymać nic zamiast wyjątku dla nieprawidłowych nazw tabel. Zobacz:
- Jak sprawdzić, czy tabela istnieje w danym schemacie
Jeszcze lepsze oszacowanie (przy bardzo niewielkim dodatkowym koszcie)
Możemy zrobić to, co robi planista Postgres. Cytując przykłady szacowania wierszy w instrukcji:
Te liczby są aktualne na dzień ostatniego VACUUM lub ANALYZE na stole. Następnie planista pobiera aktualną liczbę stron z tabeli (jest to tania operacja, niewymagająca skanowania tabeli). Jeśli to różni się od relpages następnie reltuples jest odpowiednio skalowany, aby uzyskać aktualną szacunkową liczbę wierszy.
Postgres używa estimate_rel_size zdefiniowane w src/backend/utils/adt/plancat.c , który obejmuje również narożny przypadek braku danych w pg_class ponieważ relacja nigdy nie została odkurzona. Możemy zrobić coś podobnego w SQL:
Minimalna forma
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
Bezpieczne i jednoznaczne
SELECT (CASE WHEN c.reltuples < 0 THEN NULL -- never vacuumed
WHEN c.relpages = 0 THEN float8 '0' -- empty table
ELSE c.reltuples / c.relpages END
* (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
)::bigint
FROM pg_class c
WHERE c.oid = 'myschema.mytable'::regclass; -- schema-qualified table here
Nie łamie się z pustymi tabelami i tabelami, które nigdy nie widziały VACUUM lub ANALYZE . Podręcznik na pg_class :
Jeśli tabela nigdy nie została jeszcze odkurzona ani przeanalizowana, reltuples zawiera -1 wskazując, że liczba wierszy jest nieznana.
Jeśli to zapytanie zwraca NULL , uruchom ANALYZE lub VACUUM do stołu i powtórz. (Alternatywnie możesz oszacować szerokość wiersza na podstawie typów kolumn, takich jak Postgres, ale jest to żmudne i podatne na błędy.)
Jeśli to zapytanie zwraca 0 , tabela wydaje się być pusta. Ale ja bym ANALYZE upewniać się. (A może sprawdź swój autovacuum ustawienia.)
Zazwyczaj block_size wynosi 8192. current_setting('block_size')::int obejmuje rzadkie wyjątki.
Kwalifikacje tabeli i schematu sprawiają, że jest on odporny na każdą search_path i zakres.
Tak czy inaczej, zapytanie konsekwentnie zajmuje mi <0,1 ms.
Więcej zasobów internetowych:
- Najczęściej zadawane pytania dotyczące Postgres Wiki
- Strony wiki Postgresa dla szacowanej liczby i wydajności count(*)
TABLESAMPLE SYSTEM (n) w Postgresie 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Jak skomentował @a_horse, dodana klauzula dla SELECT polecenie może być przydatne, jeśli statystyki w pg_class z jakiegoś powodu nie są wystarczająco aktualne. Na przykład:
- Brak
autovacuumbieganie. - Zaraz po dużym
INSERT/UPDATE/DELETE. TEMPORARYtabele (które nie są objęteautovacuum).
To dotyczy tylko losowych n % (1 w przykładzie) wybór bloków i zliczanie w nim wierszy. Większa próbka zwiększa koszty i zmniejsza błąd, Twój wybór. Dokładność zależy od większej liczby czynników:
- Rozkład wielkości wiersza. Jeśli dany blok zawiera szersze niż zwykle wiersze, liczba jest mniejsza niż zwykle itp.
- Martwe krotki lub
FILLFACTORzajmują miejsce na blok. W przypadku nierównomiernego rozmieszczenia w tabeli oszacowanie może być nieprawidłowe. - Ogólne błędy zaokrąglania.
Zazwyczaj oszacowanie z pg_class będzie szybszy i dokładniejszy.
Odpowiedź na aktualne pytanie
Najpierw muszę znać liczbę wierszy w tej tabeli, jeśli suma jest większa niż jakaś predefiniowana stała,
I czy to...
... jest możliwe w momencie, gdy licznik przekroczy moją stałą wartość, zatrzyma liczenie (i nie będzie czekał na zakończenie liczenia, aby poinformować, że liczba wierszy jest większa).
Tak. Możesz użyć podzapytania z LIMIT :
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres właściwie przestaje liczyć poza podany limit otrzymujesz dokładny i aktualny licz na maksymalnie n wiersze (500000 w przykładzie) i n Inaczej. Nie tak szybko, jak oszacowanie w pg_class jednak.