sql >> Database teknologi >  >> RDS >> PostgreSQL

Hurtig måde at opdage rækkeantallet af en tabel i PostgreSQL

At tælle rækker i store tabeller er kendt for at være langsom i PostgreSQL. MVCC-modellen kræver en fuld optælling af levende rækker for et præcist antal. Der er løsninger til at fremskynde dette dramatisk hvis optællingen ikke gør det skal være præcis som det ser ud til at være i dit tilfælde.

(Husk, at selv en "nøjagtig" optælling potentielt er død ved ankomst!)

Nøjagtigt antal

Langsom til store borde.
Med samtidige skriveoperationer kan den være forældet i det øjeblik, du får den.

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

Ekstremt hurtigt :

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

Typisk er estimatet meget tæt på. Hvor tæt, afhænger af om ANALYZE eller VACUUM er kørt nok - hvor "nok" er defineret af niveauet af skriveaktivitet til din tabel.

Sikker estimat

Ovenstående ignorerer muligheden for flere tabeller med samme navn i én database - i forskellige skemaer. For at tage højde for det:

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

Castet til bigint formaterer den real tal pænt, især for store tæller.

Bedre skøn

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

Hurtigere, enklere, sikrere, mere elegant. Se manualen om objektidentifikatortyper.

Erstat 'myschema.mytable'::regclass med to_regclass('myschema.mytable') i Postgres 9.4+ for ikke at få noget i stedet for en undtagelse for ugyldige tabelnavne. Se:

  • Sådan kontrollerer du, om en tabel findes i et givet skema

Bedre skøn endnu (for meget få ekstra omkostninger)

Vi kan gøre, hvad Postgres-planlæggeren gør. Citerer Eksempler på rækkevurdering i manualen:

Disse tal er aktuelle fra den sidste VACUUM eller ANALYZE på bordet. Planlæggeren henter derefter det aktuelle aktuelle antal sider i tabellen (dette er en billig operation, der ikke kræver en tabelscanning). Hvis det er forskelligt fra relpages derefter reltuples skaleres i overensstemmelse hermed for at nå frem til et aktuelt antal rækker-estimat.

Postgres bruger estimate_rel_size defineret i src/backend/utils/adt/plancat.c , som også dækker hjørnet af ingen data i pg_class fordi forholdet aldrig blev støvsuget. Vi kan gøre noget lignende i SQL:

Minimal form

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

Sikker og eksplicit

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

Bryder ikke med tomme tabeller og tabeller, der aldrig har set VACUUM eller ANALYZE . Manualen om pg_class :

Hvis bordet endnu aldrig er blevet støvsuget eller analyseret, reltuples indeholder -1 angiver, at rækkeantallet er ukendt.

Hvis denne forespørgsel returnerer NULL , kør ANALYZE eller VACUUM til bordet og gentag. (Alternativt kan du estimere rækkebredden baseret på kolonnetyper, som Postgres gør, men det er kedeligt og udsat for fejl.)

Hvis denne forespørgsel returnerer 0 , synes bordet at være tomt. Men jeg ville ANALYZE for at være sikker. (Og måske tjekke din autovacuum indstillinger.)

Typisk block_size er 8192. current_setting('block_size')::int dækker sjældne undtagelser.

Tabel- og skemakvalifikationer gør den immun over for enhver search_path og omfang.

Uanset hvad, tager forespørgslen konsekvent <0,1 ms for mig.

Flere webressourcer:

  • Ofte stillede spørgsmål om Postgres Wiki
  • Postgres wiki-sider for optællingsestimater og antal(*) ydeevne

TABLESAMPLE SYSTEM (n) i Postgres 9.5+

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

Ligesom @a_horse kommenterede, den tilføjede klausul for SELECT kommandoen kan være nyttig, hvis statistik i pg_class er ikke aktuelle nok af en eller anden grund. For eksempel:

  • Ingen autovacuum kører.
  • Umiddelbart efter en stor INSERT / UPDATE / DELETE .
  • TEMPORARY tabeller (som ikke er dækket af autovacuum ).

Dette ser kun på et tilfældigt n % (1 i eksemplet) valg af blokke og tæller rækker i det. En større prøve øger omkostningerne og reducerer fejlen, dit valg. Nøjagtighed afhænger af flere faktorer:

  • Fordeling af rækkestørrelse. Hvis en given blok tilfældigvis har bredere end sædvanlige rækker, er antallet lavere end normalt osv.
  • Døde tupler eller en FILLFACTOR optage plads pr. blok. Hvis det er ujævnt fordelt over bordet, kan estimatet være deaktiveret.
  • Generelle afrundingsfejl.

Typisk er estimatet fra pg_class vil være hurtigere og mere præcis.

Svar på det faktiske spørgsmål

Først skal jeg kende antallet af rækker i den tabel, hvis det samlede antal er større end en foruddefineret konstant,

Og om det ...

... er muligt i det øjeblik tællingen passerer min konstante værdi, vil den stoppe tællingen (og ikke vente med at afslutte tællingen for at informere om at rækkeantallet er større).

Ja. Du kan bruge en underforespørgsel med LIMIT :

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

Postgres stopper faktisk med at tælle ud over den givne grænse får du en nøjagtig og aktuel tæller op til n rækker (500.000 i eksemplet) og n Ellers. Ikke nær så hurtigt som estimatet i pg_class dog.



  1. SQL Server Internals:Plan Caching Pt. II – Genkompilering af planer

  2. Postgresql-kolonnen blev ikke fundet, men vises i beskrivelsen

  3. Sådan gør du RAND() deterministisk i SQL Server

  4. Definer trinene for SQL Server Cursor - SQL Server / TSQL Tutorial