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

Un modo rapido per scoprire il conteggio delle righe di una tabella in PostgreSQL

Il conteggio delle righe nelle tabelle grandi è noto per essere lento in PostgreSQL. Il modello MVCC richiede un conteggio completo delle righe live per un numero preciso. Esistono soluzioni alternative per accelerare notevolmente se il conteggio non devono essere esatti come sembra essere nel tuo caso.

(Ricorda che anche un conteggio "esatto" è potenzialmente morto all'arrivo!)

Conteggio esatto

Lento per grandi tabelle.
Con operazioni di scrittura simultanee, potrebbe essere obsoleto nel momento in cui lo ottieni.

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

Estremamente veloce :

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

In genere, la stima è molto vicina. Quanto vicino, dipende se ANALYZE o VACUUM sono abbastanza eseguiti - dove "abbastanza" è definito dal livello di attività di scrittura sulla tabella.

Stima più sicura

Quanto sopra ignora la possibilità di più tabelle con lo stesso nome in un database, in schemi diversi. Per tenerne conto:

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

Il cast di bigint formatta il real numero bene, soprattutto per grandi conteggi.

Migliore stima

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

Più veloce, più semplice, più sicuro, più elegante. Consulta il manuale sui tipi di identificatore oggetto.

Sostituisci 'myschema.mytable'::regclass con to_regclass('myschema.mytable') in Postgres 9.4+ per non ottenere nulla invece di un'eccezione per nomi di tabelle non validi. Vedi:

  • Come verificare se esiste una tabella in un determinato schema

Stima ancora migliore (a un costo aggiuntivo minimo)

Possiamo fare quello che fa il pianificatore Postgres. Citando gli Esempi di stima delle righe nel manuale:

Questi numeri sono aggiornati all'ultimo VACUUM o ANALYZE sul tavolo. Il pianificatore quindi recupera il numero effettivo attuale di pagine nella tabella (questa è un'operazione economica, che non richiede una scansione della tabella). Se è diverso da relpages quindi reltuples viene ridimensionato di conseguenza per arrivare a una stima del numero di righe corrente.

Postgres usa estimate_rel_size definito in src/backend/utils/adt/plancat.c , che copre anche il caso d'angolo dell'assenza di dati in pg_class perché il rapporto non è mai stato aspirato. Possiamo fare qualcosa di simile in SQL:

Forma minima

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

Sicuro ed esplicito

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

Non si interrompe con tabelle vuote e tabelle che non hanno mai visto VACUUM o ANALYZE . Il manuale su pg_class :

Se il tavolo non è mai stato passato sottovuoto o analizzato, reltuples contiene -1 indicando che il conteggio delle righe è sconosciuto.

Se questa query restituisce NULL , esegui ANALYZE o VACUUM per la tavola e ripetere. (In alternativa, puoi stimare la larghezza della riga in base ai tipi di colonna come fa Postgres, ma è noioso e soggetto a errori.)

Se questa query restituisce 0 , il tavolo sembra vuoto. Ma vorrei ANALYZE assicurarsi. (E magari controlla il tuo autovacuum impostazioni.)

In genere, block_size è 8192. current_setting('block_size')::int copre rare eccezioni.

Le qualifiche di tabelle e schemi lo rendono immune a qualsiasi search_path e portata.

Ad ogni modo, la query richiede costantemente <0,1 ms per me.

Altre risorse Web:

  • Domande frequenti sul Wiki di Postgres
  • Le pagine wiki di Postgres per le stime dei conteggi e le prestazioni dei conteggi(*)

TABLESAMPLE SYSTEM (n) in Postgres 9.5+

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

Come ha commentato @a_horse, la clausola aggiunta per SELECT il comando può essere utile se le statistiche in pg_class non sono abbastanza attuali per qualche motivo. Ad esempio:

  • Nessun autovacuum in esecuzione.
  • Subito dopo un INSERT grande / UPDATE / DELETE .
  • TEMPORARY tabelle (che non sono coperte da autovacuum ).

Questo esamina solo un n casuale % (1 nell'esempio) la selezione dei blocchi e il conteggio delle righe al suo interno. Un campione più grande aumenta il costo e riduce l'errore, la tua scelta. La precisione dipende da più fattori:

  • Distribuzione della dimensione della riga. Se un determinato blocco contiene righe più larghe del solito, il conteggio è inferiore al solito, ecc.
  • Tuple morte o un FILLFACTOR occupare spazio per blocco. Se distribuita in modo non uniforme sul tavolo, la stima potrebbe non essere valida.
  • Errori di arrotondamento generali.

In genere, la stima di pg_class sarà più veloce e preciso.

Risposta alla domanda attuale

Innanzitutto, ho bisogno di conoscere il numero di righe in quella tabella, se il totalcount è maggiore di una costante predefinita,

E se ...

... è possibile nel momento in cui il conteggio supera il mio valore costante, interromperà il conteggio (e non aspetta di finire il conteggio per informare che il conteggio delle righe è maggiore).

Sì. Puoi utilizzare una sottoquery con LIMIT :

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

Postgres in realtà smette di contare oltre il limite indicato, ottieni un valore esatto e attuale contare fino a n righe (500000 nell'esempio) e n altrimenti. Non così veloce come la stima in pg_class , però.