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 daautovacuum
).
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ò.