sql >> Database >  >> RDS >> PostgreSQL

Snelle manier om het aantal rijen van een tabel te ontdekken in PostgreSQL

Het is bekend dat het tellen van rijen in grote tabellen traag is in PostgreSQL. Het MVCC-model vereist een volledige telling van live-rijen voor een nauwkeurig aantal. Er zijn oplossingen om dit drastisch te versnellen als de telling niet doet moet exact zijn zoals het in jouw geval lijkt te zijn.

(Vergeet niet dat zelfs een "exacte" telling mogelijk dood is bij aankomst!)

Exact aantal

Langzaam voor grote tabellen.
Met gelijktijdige schrijfbewerkingen kan het verouderd zijn op het moment dat u het krijgt.

SELECT count(*) AS exact_count FROM myschema.mytable;
Schatting

Extreem snel :

SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';

Meestal is de schatting heel dichtbij. Hoe dichtbij, hangt af van of ANALYZE of VACUUM genoeg worden uitgevoerd - waarbij "genoeg" wordt gedefinieerd door het niveau van schrijfactiviteit naar uw tabel.

Veiligere schatting

Het bovenstaande negeert de mogelijkheid van meerdere tabellen met dezelfde naam in één database - in verschillende schema's. Om daar rekening mee te houden:

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';

De cast naar bigint formatteert de real nummer mooi, vooral voor grote tellingen.

Betere schatting

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;

Sneller, eenvoudiger, veiliger, eleganter. Zie de handleiding over Object Identifier Types.

Vervang 'myschema.mytable'::regclass met to_regclass('myschema.mytable') in Postgres 9.4+ om niets te krijgen in plaats van een uitzondering voor ongeldige tabelnamen. Zie:

  • Hoe te controleren of een tabel in een bepaald schema bestaat

Nog betere schatting (tegen zeer weinig extra kosten)

Wij kunnen doen wat de Postgres planner doet. Citaat van de Voorbeelden van rijschattingen in de handleiding:

Deze nummers zijn actueel vanaf de laatste VACUUM of ANALYZE op de tafel. De planner haalt dan het actuele aantal pagina's in de tabel op (dit is een goedkope handeling, waarvoor geen tabelscan nodig is). Als dat anders is dan relpages dan reltuples wordt overeenkomstig geschaald om tot een huidige schatting van het aantal rijen te komen.

Postgres gebruikt estimate_rel_size gedefinieerd in src/backend/utils/adt/plancat.c , die ook het hoekgeval van geen gegevens dekt in pg_class omdat de relatie nooit is gestofzuigd. We kunnen iets soortgelijks doen in SQL:

Minimale vorm

SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM   pg_class
WHERE  oid = 'mytable'::regclass;  -- your table here

Veilig en expliciet

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

Breekt niet met lege tabellen en tabellen die nog nooit VACUUM hebben gezien of ANALYZE . De handleiding op pg_class :

Als de tafel nog nooit is gestofzuigd of geanalyseerd, reltuples bevat -1 wat aangeeft dat het aantal rijen onbekend is.

Als deze zoekopdracht NULL retourneert , voer ANALYZE uit of VACUUM voor de tafel en herhaal. (U kunt ook de rijbreedte schatten op basis van kolomtypen zoals Postgres doet, maar dat is vervelend en foutgevoelig.)

Als deze zoekopdracht 0 oplevert , lijkt de tafel leeg te zijn. Maar ik zou ANALYZE om er zeker van te zijn. (En misschien controleer je autovacuum instellingen.)

Meestal block_size is 8192. current_setting('block_size')::int dekt zeldzame uitzonderingen.

Tabel- en schemakwalificaties maken het immuun voor elk search_path en reikwijdte.

Hoe dan ook, de query duurt bij mij consequent <0,1 ms.

Meer internetbronnen:

  • Veelgestelde vragen over Postgres Wiki
  • De Postgres-wikipagina's voor schattingen van tellingen en prestaties van telling(*)

TABLESAMPLE SYSTEM (n) in Postgres 9.5+

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);

Zoals @a_horse opmerkte, de toegevoegde clausule voor de SELECT commando kan handig zijn als statistieken in pg_class zijn om de een of andere reden niet actueel genoeg. Bijvoorbeeld:

  • Geen autovacuum rennen.
  • Onmiddellijk na een grote INSERT / UPDATE / DELETE .
  • TEMPORARY tabellen (die niet worden gedekt door autovacuum ).

Dit kijkt alleen naar een willekeurige n % (1 in het voorbeeld) selectie van blokken en telt rijen daarin. Een groter monster verhoogt de kosten en vermindert de fout, uw keuze. Nauwkeurigheid hangt van meer factoren af:

  • Verdeling van rijgrootte. Als een bepaald blok bredere rijen heeft dan normaal, is de telling lager dan normaal, enz.
  • Dode tuples of een FILLFACTOR ruimte per blok innemen. Indien ongelijk verdeeld over de tafel, kan de schatting niet kloppen.
  • Algemene afrondingsfouten.

Meestal is de schatting van pg_class zal sneller en nauwkeuriger zijn.

Antwoord op de eigenlijke vraag

Eerst moet ik het aantal rijen in die tabel weten, als het totaalaantal groter is dan een vooraf gedefinieerde constante,

En of het ...

... is mogelijk op het moment dat de telling mijn constante waarde overschrijdt, zal het het tellen stoppen (en niet wachten om het tellen te voltooien om te informeren dat het aantal rijen groter is).

Ja. U kunt een subquery gebruiken met LIMIT :

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

Postgres stopt eigenlijk met tellen boven de gegeven limiet, krijg je een exacte en actuele tel tot n rijen (500000 in het voorbeeld), en n anders. Lang niet zo snel als de schatting in pg_class , hoewel.



  1. Rollen en statussen in een systeem beheren

  2. Top tien MySQL GUI-tools

  3. Zijn beperkingen van externe sleutels van invloed op querytransformaties in Oracle?

  4. Installeer Web Server in Windows XP met Apache2, PHP5 en MySQL4 – Deel 4