sql >> Databáze >  >> RDS >> PostgreSQL

Rychlý způsob, jak zjistit počet řádků tabulky v PostgreSQL

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 nebo ANALYZE 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ší od relpages 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 nevztahuje autovacuum ).

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.



  1. Chyba SQL Oracle LEFT JOIN a SUBQUERY:ORA-00905:chybějící klíčové slovo

  2. MySQL – Jak zrušit tabulku, pokud existuje v databázi?

  3. JSON_CONTAINS_PATH() Příklady v MySQL

  4. Jak vytvořit menu v SQLPlus nebo PL/SQL