Je známo, že počítání řádků ve velkých tabulkách je v PostgreSQL pomalé. Model MVCC vyžaduje plný počet aktivních řádků pro přesné číslo. Existují zástupná řešení, jak to dramaticky urychlit pokud počet ne musí být přesné jako by to bylo ve vašem případě.
(Nezapomeňte, že i „přesný“ počet je při příjezdu potenciálně mrtvý!)
Přesný počet
Pomalý pro velké tabulky.
Při souběžných operacích zápisu může být zastaralý v okamžiku, kdy jej získáte.
SELECT count(*) AS exact_count FROM myschema.mytable;
Odhad
Extrémně rychlé :
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
Obvykle je odhad velmi blízko. Jak blízko, závisí na tom, zda ANALYZE
nebo VACUUM
jsou dostatečně spuštěny – kde „dost“ je definováno úrovní aktivity zápisu do vaší tabulky.
Bezpečnější odhad
Výše uvedené ignoruje možnost více tabulek se stejným názvem v jedné databázi – v různých schématech. Chcete-li to zohlednit:
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';
Obsazení do bigint
formátuje real
číslo pěkně, zvláště pro velké počty.
Lepší odhad
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
Rychlejší, jednodušší, bezpečnější, elegantnější. Viz příručka Typy identifikátorů objektů.
Nahraďte 'myschema.mytable'::regclass
pomocí to_regclass('myschema.mytable')
v Postgres 9.4+, abyste místo výjimky pro neplatné názvy tabulek nezískali nic. Viz:
- Jak zkontrolovat, zda tabulka v daném schématu existuje
Ještě lepší odhad (za velmi malé dodatečné náklady)
Můžeme dělat to, co dělá plánovač Postgres. Citace Příklady odhadu řádků v návodu:
Tato čísla jsou aktuální k poslednímu
VACUUM
neboANALYZE
na stole. Plánovač pak načte aktuální aktuální počet stránek v tabulce (jedná se o levnou operaci, která nevyžaduje skenování tabulky). Pokud se to liší odrelpages
a potéreltuples
je škálováno podle toho, aby se dospělo k aktuálnímu odhadu počtu řádků.
Postgres používá estimate_rel_size
definované v src/backend/utils/adt/plancat.c
, který také pokrývá rohový případ bez dat v pg_class
protože vztah nebyl nikdy vysát. Něco podobného můžeme udělat v SQL:
Minimální forma
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
Bezpečné a explicitní
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
Nerozbije se prázdnými tabulkami a tabulkami, které nikdy neviděly VACUUM
nebo ANALYZE
. Manuál na pg_class
:
Pokud stůl ještě nikdy nebyl vysát nebo analyzován,
reltuples
obsahuje-1
což znamená, že počet řádků je neznámý.
Pokud tento dotaz vrátí NULL
, spusťte ANALYZE
nebo VACUUM
pro stůl a opakujte. (Případně můžete odhadnout šířku řádku na základě typů sloupců, jako to dělá Postgres, ale to je zdlouhavé a náchylné k chybám.)
Pokud tento dotaz vrátí 0
, stůl se zdá být prázdný. Ale já bych ANALYZE
aby se ujistil. (A možná zkontrolujte svůj autovacuum
nastavení.)
Obvykle block_size
je 8192. current_setting('block_size')::int
pokrývá vzácné výjimky.
Kvalifikace tabulek a schémat jej činí imunním vůči jakékoli search_path
a rozsah.
V každém případě mi dotaz trvale trvá <0,1 ms.
Další webové zdroje:
- Časté dotazy k Postgres Wiki
- Stránky wiki Postgres pro odhady počtu a výkon počtu (*)
TABLESAMPLE SYSTEM (n)
v Postgres 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Stejně jako v komentáři @a_horse byla přidána klauzule pro SELECT
příkaz může být užitečný, pokud statistiky v pg_class
nejsou z nějakého důvodu dostatečně aktuální. Například:
- Žádné
autovacuum
běží. - Ihned po velkém
INSERT
/UPDATE
/DELETE
. TEMPORARY
tabulky (na které se nevztahujeautovacuum
).
Toto se podívá pouze na náhodné n % (1
v příkladu) výběr bloků a počítání řádků v něm. Větší vzorek zvyšuje náklady a snižuje chyby, váš výběr. Přesnost závisí na více faktorech:
- Rozdělení velikosti řádku. Pokud se stane, že daný blok obsahuje řádky širší než obvykle, počet je nižší než obvykle atd.
- Mrtvé n-tice nebo
FILLFACTOR
zabírat prostor na blok. Při nerovnoměrném rozložení v tabulce může být odhad mimo. - Obecné chyby zaokrouhlování.
Obvykle odhad z pg_class
bude rychlejší a přesnější.
Odpověď na aktuální otázku
Nejprve potřebuji znát počet řádků v této tabulce, pokud je celkový počet větší než nějaká předdefinovaná konstanta,
A ať už ...
... je možné v okamžiku, kdy počet překročí moji konstantní hodnotu, zastaví počítání (a nečeká na dokončení počítání, aby informoval, že počet řádků je větší).
Ano. Můžete použít poddotaz s LIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres ve skutečnosti přestane počítat za daným limitem získáte přesný a aktuální počítejte do n řádky (v příkladu 500 000) a n v opačném případě. Ne tak rychle jako odhad v pg_class
, ačkoli.