Il modo più veloce per contare il numero esatto di righe in una tabella molto grande?


234

Mi sono imbattuto in articoli che affermano che SELECT COUNT(*) FROM TABLE_NAMEsarà lento quando la tabella ha molte righe e molte colonne.

Ho una tabella che potrebbe contenere anche miliardi di righe [ha circa 15 colonne]. C'è un modo migliore per ottenere il conteggio EXACT del numero di righe di una tabella?

Si prega di considerare quanto segue prima della risposta:

  • Sto cercando una soluzione indipendente dal fornitore di database. Va bene se copre MySQL , Oracle , MS SQL Server . Ma se davvero non esiste una soluzione indipendente per i fornitori di database, mi accontenterò di soluzioni diverse per i diversi fornitori di database.

  • Non posso usare nessun altro strumento esterno per farlo. Sono principalmente alla ricerca di una soluzione basata su SQL.

  • Non posso più normalizzare la progettazione del mio database. È già in 3NF e inoltre un sacco di codice è già stato scritto attorno ad esso.


4
E solo curioso di
sapere

2
Non speriamo tutti che questo particolare costrutto sia stato ottimizzato dal nostro fornitore di database?
KevinDTimm,

5
@Swaranga, puoi chiarire un po 'di più su quale sia lo scopo di manutenzione del database che deve conoscere il numero esatto di righe nella tabella? Non riesco a immaginare. E come dice Kevin, se ci fosse un modo più veloce di COUNT (*), il fornitore DBMS (dovrebbe) sicuramente implementerebbe nuovamente COUNT (*) per usarlo ...
Tony Andrews,

3
Sicuramente se la tabella viene scritta spesso, il conteggio esatto sarà esatto solo per un determinato momento e potrebbe non essere accurato se altri processi stanno scrivendo sulla tabella, a meno che non si inserisca un blocco della tabella nella query.
Steve Ford,

2
È possibile utilizzare i trigger di inserimento ed eliminazione per mantenere un conteggio progressivo?
paparazzo,

Risposte:


246

Risposta semplice:

  • Soluzione indipendente dal fornitore del database = usa lo standard = COUNT(*)
  • Esistono soluzioni approssimative di SQL Server ma non utilizzare COUNT (*) = fuori ambito

Appunti:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey) per ogni evenienza

Modificare:

Esempio di SQL Server (1,4 miliardi di righe, 12 colonne)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 corse, 5:46 minuti, conteggio = 1.401.659.700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2 corse, entrambe in meno di 1 secondo, contano = 1.401.659.670

Il secondo ha meno righe = sbagliato. Sarebbe lo stesso o più a seconda delle scritture (le eliminazioni vengono eseguite fuori orario qui)


9
No, COUNT(*) = COUNT(key). Questo è semplicemente sbagliato. Se non ci sono NOT NULLvincoli, possono non essere uguali (nei risultati e nel piano di esecuzione).
zerkms,

14
@zerkmsby: per COUNT (chiave) intendevo COUNT (chiave primaria) che dovrebbe essere non annullabile. Io chiarire
gbn

8
con (NOLOCK) non è qualcosa che gli consente di funzionare in produzione e può portare a un conteggio impreciso. Quando si utilizza quel suggerimento, assicurarsi che impedisca i blocchi, ma gli effetti collaterali su una casella di produzione sono che è possibile contare le righe due volte in alcune situazioni o saltare le righe in altre situazioni. È preferibile utilizzare NOLOCK su una tabella in cui non viene scritto perché consente "letture sporche". Non consigliare alle persone di usare quel suggerimento a meno che non comprendano appieno le conseguenze
Davos,

4
@mishrsud L'unica query accurata è SELECT COUNT (*), ma è lenta. Puoi avere esatto e lento, o approssimativo e veloce. Quello che fai dipenderà da ciò che è più importante per lo scopo per cui hai bisogno di contare. NO LOCK potrebbe includere o addirittura escludere righe che sono transazioni intermedie o pagine in movimento per qualsiasi motivo.
Davos,

5
@gbn soluzione molto bella, puoi dire a cosa serve index_id < 2?
commetti il

29

Il modo più veloce di gran lunga su MySQL è:

SHOW TABLE STATUS;

Riceverai immediatamente tutti i tuoi tavoli con il conteggio delle righe (che è il totale) insieme a molte altre informazioni se lo desideri.


1
Modo intelligente ... con questo è possibile ottenere il conteggio delle righe di più tabelle in 1 query.
Deval Khandelwal,

hai eseguito un db con tabelle con ~ miliardi di voci come @gbn e hai notato l'ora?
KNU,

quale valore è il conteggio totale delle righe per tutte le tabelle nel database? E questi sono approssimativi: cosa succede se si desidera un conteggio esatto delle righe?
Kreeverp,

2
questo non funziona affatto, ad esempio su INNODB, il motore di archiviazione legge alcune righe ed estrapola per indovinare il numero di righe
Martijn Scheffer,

10

Ho trovato articoli che affermano che SELECT COUNT (*) FROM TABLE_NAME sarà lento quando la tabella ha molte righe e molte colonne.

Dipende dal database. Alcuni conteggi accelerati, ad esempio tenendo traccia del fatto che le righe siano attive o morte nell'indice, consentendo a un solo indice di scansione di estrarre il numero di righe. Altri no, e di conseguenza richiedono di visitare l'intera tabella e di contare le righe live una per una. O sarà lento per un tavolo enorme.

Si noti che in genere è possibile estrarre una buona stima utilizzando strumenti di ottimizzazione delle query, statistiche delle tabelle, ecc. Nel caso di PostgreSQL, ad esempio, è possibile analizzare l'output di explain count(*) from yourtablee ottenere una stima ragionevolmente buona del numero di righe. Il che mi porta alla tua seconda domanda.

Ho una tabella che potrebbe contenere anche miliardi di righe [ha circa 15 colonne]. Esiste un modo migliore per ottenere il conteggio EXACT del numero di righe di una tabella?

Sul serio? :-) Intendi davvero il conteggio esatto da una tabella con miliardi di righe? Ne sei davvero sicuro? :-)

Se lo fai davvero , potresti tenere traccia del totale usando i trigger, ma fai attenzione a concorrenza e deadlock se lo fai.


Sì Denis, è richiesto il conteggio esatto. :(
Swaranga Sarma,

5
È una fortuna che i gestori di Google siano più ragionevoli del tuo capo ... Immagina quanto sarebbe lento se restituisse il numero esatto di risultati di ricerca per ciascuna delle tue query invece di attenersi a un numero di stima.
Denis de Bernardy,

Almeno ti immedesimi in me. Che ne dici di un'unica soluzione Oracle? Ciò ridurrà il mio problema in una certa misura. Attualmente il cliente utilizza Oracle; quindi, se trovo una soluzione alternativa solo per Oracle, lo farà [per il momento]. :)
Swaranga Sarma,

6
"Sì Denis, è richiesto il conteggio esatto. :(" - beh, posso solo speculare. Il processo di manutenzione del db scopre che ci sono 42.123.876 righe nella tabella A e quindi crea 42.123.876 righe vuote nella tabella B, quindi passa in rassegna la tabella A e aggiorna le righe nella tabella B ...? O è più folle di così? ;-)
Tony Andrews,

1
La transazione 2 non può iniziare prima del commit della transazione 1. Senza l'aggiornamento della "tabella dei conteggi", molte transazioni di aggiornamento potrebbero essere eseguite in parallelo. Con la "tabella dei conteggi", ogni transazione deve "ottenere un ticket" per aggiornare il suo conteggio. Quindi le transazioni iniziano a fare la fila al distributore di biglietti (lo scheduler decide chi sarà il prossimo a ottenere un blocco sulla tabella dei conteggi).
Erwin Smout,

10

Esiste un modo migliore per ottenere il conteggio EXACT del numero di righe di una tabella?

Per rispondere semplicemente alla tua domanda, No .

Se hai bisogno di un modo indipendente da DBMS per farlo, il modo più veloce sarà sempre:

SELECT COUNT(*) FROM TableName

Alcuni fornitori di DBMS potrebbero avere modi più rapidi che funzioneranno solo per i loro sistemi. Alcune di queste opzioni sono già pubblicate in altre risposte.

COUNT(*) dovrebbe essere ottimizzato dal DBMS (almeno qualsiasi DB degno di PROD) comunque, quindi non cercare di aggirare le loro ottimizzazioni.

Nota a margine:
sono sicuro che anche molte altre tue domande impiegheranno molto tempo a terminare a causa delle dimensioni del tuo tavolo. Eventuali problemi di prestazioni dovrebbero probabilmente essere affrontati pensando alla progettazione dello schema tenendo presente la velocità. Mi rendo conto che hai detto che non è un'opzione da modificare, ma potrebbe anche rivelarsi che le query di oltre 10 minuti non siano un'opzione. 3rd NF non è sempre l'approccio migliore quando è necessaria la velocità, e talvolta i dati possono essere partizionati in più tabelle se i record non devono essere archiviati insieme. Qualcosa a cui pensare...


10

Ho ricevuto questo script da un'altra domanda / risposta StackOverflow:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

La mia tabella ha 500 milioni di record e i rendimenti sopra riportati in meno di 1 ms. Nel frattempo,

SELECT COUNT(id) FROM MyTable

impiega 39 minuti, 52 secondi!

Forniscono lo stesso numero esatto di righe (nel mio caso, esattamente 519326012).

Non so se sarebbe sempre così.


Puoi aggiungere un parametro per ottenere il conteggio delle righe con questa query? Esempio: selezionare COUNT (1) DA TABLENAME DOVE ColumnFiled = '1' Con la tua query?
VnDevil,

Questo è il conteggio - il numero di righe (record) è il "conteggio" in questo caso. "500 milioni di record" era un numero approssimativo e "519326012" era il numero esatto di righe o conteggi. Righe = record = conteggio.
JakeJ,

9

Puoi provare questo sp_spaceused (Transact-SQL)

Visualizza il numero di righe, spazio su disco riservato e spazio su disco utilizzato da una tabella, vista indicizzata o coda di Service Broker nel database corrente oppure visualizza lo spazio su disco riservato e utilizzato da tutto il database.


Sp_spaceused non mi darà un conteggio approssimativo?
Swaranga Sarma,

1
A proposito: utilizza sys.dm_db_partition_stats internamente
gbn

6

Se l'edizione di SQL Server è 2005/2008, è possibile utilizzare i DMV per calcolare il conteggio delle righe in una tabella:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

Per il motore di database di SQL Server 2000, sysindexes funzionerà, ma si consiglia vivamente di evitare di utilizzarlo nelle future edizioni di SQL Server poiché potrebbe essere rimosso nel prossimo futuro.

Codice di esempio tratto da: Come ottenere i conteggi delle righe della tabella in modo rapido e indolore


Questo è approssimativo non esatto : vedi la mia risposta per favore
gbn

Conosci un esempio in cui questo non è accurato? AFAIK, non dipende da statistiche aggiornate.
Alireza Maddah,

5

Io uso

select /*+ parallel(a) */  count(1) from table_name a;

seleziona / * + parallel (a) * / count (1) da table_name a
Mainsh S

5

Non sono per nulla esperto quanto gli altri che hanno risposto ma avevo un problema con una procedura che stavo usando per selezionare una riga casuale da una tabella (non eccessivamente rilevante) ma dovevo conoscere il numero di righe nella mia tabella di riferimento per calcolare l'indice casuale. Usando il tradizionale conteggio (*) o il conteggio (1) lavoro, occasionalmente stavo ottenendo fino a 2 secondi per l'esecuzione della mia query. Quindi invece (per la mia tabella denominata 'tbl_HighOrder') sto usando:

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

Funziona benissimo e i tempi di interrogazione in Management Studio sono zero.


1
FWIW, dovresti menzionare QUALE fornitore di database stai usando; Penso che la dichiarazione sarebbe leggermente diversa a seconda del fornitore.
ToolmakerSteve

5

Bene, in ritardo di 5 anni e incerto se aiuta:

Stavo cercando di contare il no. di righe in una tabella di SQL Server utilizzando MS SQL Server Management Studio e si è verificato un errore di overflow, quindi ho utilizzato quanto segue:

seleziona count_big (1) FROM [dbname]. [dbo]. [FactSampleValue];

Il risultato :

24296650578 righe


5

Ho trovato questo buon articolo SQL Server – HOW-TO: recuperare rapidamente il conteggio delle righe accurato per la tabella da martijnh1cui fornisce un buon riepilogo per ogni scenario.

Ho bisogno che questo sia espanso dove devo fornire un conteggio basato su una condizione specifica e quando immagino questa parte, aggiornerò ulteriormente questa risposta.

Nel frattempo, ecco i dettagli dall'articolo:

Metodo 1:

Query:

SELECT COUNT(*) FROM Transactions 

Commenti:

Esegue una scansione della tabella completa. Lento su grandi tavoli.

Metodo 2:

Query:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

Commenti:

Modo rapido per recuperare il conteggio delle righe. Dipende dalle statistiche ed è impreciso.

Eseguire DBCC UPDATEUSAGE (Database) WITH COUNT_ROWS, che può richiedere molto tempo per tabelle di grandi dimensioni.

Metodo 3:

Query:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

Commenti:

Il modo in cui lo studio di gestione SQL conta le righe (guarda le proprietà della tabella, l'archiviazione, il conteggio delle righe). Molto veloce, ma comunque un numero approssimativo di righe.

Metodo 4:

Query:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

Commenti:

Operazione rapida (anche se non altrettanto rapida del metodo 2) e altrettanto importante, affidabile.


Grazie! Suggerimento davvero utile. Non ho l'autorizzazione per visualizzare le tabelle di sistema, quindi il metodo 4 non sono io. Tuttavia, il metodo 3 è abbastanza buono.
Nicholas Humphrey,

3

Non credo che esista una soluzione generale sempre più veloce: alcune versioni / RDBMS hanno un'ottimizzazione specifica per l' SELECT COUNT(*)utilizzo di opzioni più veloci, mentre altre eseguono semplicemente la scansione della tabella. Dovresti andare ai siti di documentazione / supporto per il secondo set, che probabilmente avrà bisogno di qualche query più specifica da scrivere, di solito uno che colpisce un indice in qualche modo.

MODIFICARE:

Ecco un pensiero che potrebbe funzionare, a seconda del tuo schema e della distribuzione dei dati: hai una colonna indicizzata che fa riferimento a un valore crescente, un ID crescente numerico, diciamo, o anche un timestamp o una data? Quindi, supponendo che le eliminazioni non avvengano, dovrebbe essere possibile memorizzare il conteggio fino a un valore recente (data di ieri, valore ID più alto in un punto campione recente) e aggiungere il conteggio oltre quello, che dovrebbe risolversi molto rapidamente nell'indice . Molto dipendente da valori e indici, ovviamente, ma applicabile praticamente a qualsiasi versione di qualsiasi DBMS.


Spero vivamente che qualsiasi DBMS decente utilizzi un indice per SELECT COUNT(*). Anche MySQL a quanto pare lo fa ....
sleske,

supponendo che le cancellazioni non avvengano - sul serio ?? ; p
ToolmakerSteve

3

Sono in ritardo con questa domanda, ma ecco cosa puoi fare con MySQL (mentre uso MySQL). Sto condividendo le mie osservazioni qui:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>

Risultato
Conteggio righe : 508534
Output console: Righe interessate: 0 Righe trovate: 1 Avvertenze: 0 Durata per 1 query: 0,125 sec.
Richiede del tempo per una tabella con un numero elevato di righe, ma il conteggio delle righe è molto preciso.

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"

Risultato
Conteggio righe : 511235
Output console: Righe interessate: 0 Righe trovate: 1 Avvertenze: 0 Durata per 1 query: 0,250 sec Riepilogo: Il conteggio delle righe non è esatto.

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

Risultato
Conteggio righe : 507806
Output console: Righe interessate: 0 Righe trovate: 48 Avvertenze: 0 Durata per 1 query: 1.701 sec.
Il conteggio delle righe non è esatto.

Non sono un esperto di database o MySQL, ma ho scoperto che per tabelle molto grandi, puoi usare l'opzione 2 o 3 e avere una 'buona idea' di quante righe sono presenti.

Avevo bisogno di ottenere questi conteggi delle righe per visualizzare alcune statistiche sull'interfaccia utente. Con le query precedenti, sapevo che le righe totali erano più di 500.000, quindi mi è venuta in mente di mostrare statistiche come "Più di 500.000 righe" senza mostrare il numero esatto di righe.

Forse non ho davvero risposto alla domanda del PO, ma condivido ciò che ho fatto in una situazione in cui tali statistiche erano necessarie. Nel mio caso, mostrare le righe approssimative era accettabile e quindi quanto sopra ha funzionato per me.


2

Non esattamente una soluzione indipendente da DBMS, ma almeno il codice client non vedrà la differenza ...

Crea un'altra tabella T con solo una riga e un campo intero N 1 e crea INSERT TRIGGER che esegue:

UPDATE T SET N = N + 1

Crea anche un DELETE TRIGGER che esegue:

UPDATE T SET N = N - 1

Un DBMS degno del suo sale garantirà l'atomicità delle operazioni sopra 2 e N conterrà il conteggio accurato delle righe in ogni momento, che è quindi super rapido da ottenere semplicemente:

SELECT N FROM T

Mentre i trigger sono specifici del DBMS, la selezione da T non lo è e il codice client non dovrà cambiare per ogni DBMS supportato.

Tuttavia, ciò può avere alcuni problemi di scalabilità se la tabella è INSERT o DELETE ad alta intensità, specialmente se non COMMIT immediatamente dopo INSERT / DELETE.


1 Questi nomi sono solo segnaposto: utilizzare qualcosa di più significativo nella produzione.

2 Ie N non può essere modificato da una transazione simultanea tra lettura e scrittura su N, purché sia ​​la lettura che la scrittura vengano eseguite in una singola istruzione SQL.


2

Una risposta letteralmente folle, ma se hai un qualche tipo di sistema di replica impostato (per un sistema con un miliardo di righe, spero che tu lo faccia), puoi usare uno stimatore approssimativo (come MAX(pk)), dividere quel valore per il numero di slave hai eseguito diverse query in parallelo.

Per la maggior parte, partizioneresti le query tra gli slave in base alla chiave migliore (o alla chiave primaria immagino), in modo tale (useremo 250000000 come le nostre righe / slave):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

Ma hai bisogno solo di SQL. Che busto. Ok, allora diciamo che sei un sadomasochista. Sul master (o slave più vicino) molto probabilmente avresti bisogno di creare una tabella per questo:

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

Quindi invece di avere solo i selettori in esecuzione nei tuoi schiavi, dovresti fare un inserto, simile a questo:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

È possibile che si verifichino problemi con gli slave che scrivono su una tabella del master. Potrebbe essere necessario ottenere ancora più sadici, voglio dire, creativo:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

Alla fine dovresti avere uno slave che esiste per ultimo nel percorso attraversato dal grafico di replica, rispetto al primo slave. Lo slave dovrebbe ora avere tutti gli altri valori del contatore e dovrebbe avere i propri valori. Ma quando hai finito, probabilmente ci sono delle righe aggiunte, quindi dovresti inserirne un altro per compensare il pk massimo registrato nella tua counter_table e il pk massimo corrente.

A quel punto, dovresti fare una funzione aggregata per capire quali sono le righe totali, ma è più facile dato che le eseguiresti al massimo sul "numero di slave che hai e cambi".

Se ti trovi nella situazione in cui hai tabelle separate negli slave, puoi UNIONottenere tutte le file di cui hai bisogno.

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

O sai, sii un po 'meno pazzo e migra i tuoi dati su un sistema di elaborazione distribuito, o magari usa una soluzione di Data Warehousing (che ti darà un fantastico scricchiolio dei dati anche in futuro).

Nota, questo dipende da quanto è impostata la tua replica. Poiché il collo di bottiglia primario sarà molto probabilmente l'archiviazione persistente, se si dispone di memoria grezza o archivi di dati scarsamente separati con un forte rumore del vicino, questo probabilmente ti farà rallentare piuttosto che aspettare un singoloSELECT COUNT(*) ...

Ma se hai una buona replica, allora i tuoi guadagni di velocità dovrebbero essere direttamente correlati al numero o agli slave. In effetti, se sono necessari 10 minuti per eseguire la query di conteggio da solo e si dispone di 8 slave, si ridurrebbe il tempo a meno di un paio di minuti. Forse un'ora per appianare i dettagli di questa soluzione.

Certo, non otterrai mai una risposta incredibilmente accurata poiché questa soluzione distribuita introduce un po 'di tempo in cui le righe possono essere eliminate e inserite, ma puoi provare a ottenere un blocco distribuito di righe nella stessa istanza e ottenere un conteggio preciso delle righe nella tabella per un momento particolare nel tempo.

In realtà, questo sembra impossibile, dal momento che sei praticamente bloccato con una soluzione solo SQL, e non penso che ti sia stato fornito un meccanismo per eseguire una query frammentata e bloccata su più slave, all'istante. Forse se avessi il controllo del file di registro di replica ... il che significa che avresti letteralmente fatto girare gli schiavi per questo scopo, che è senza dubbio più lento della semplice esecuzione della query di conteggio su una singola macchina.

Quindi ci sono i miei due penny del 2013.


2

Se il trigger di inserimento è troppo costoso da utilizzare, ma è possibile fornire un trigger di eliminazione e si verifica un incremento automaticoid , dopo aver contato l'intera tabella una volta e ricordando il conteggio come last-counte illast-counted-id ,

quindi ogni giorno basta contare id> last-counted-id, aggiungerlo a last-counte archiviare il nuovolast-counted-id .

Il trigger di eliminazione decrementerebbe l'ultimo conteggio, se ID del record eliminato <= ultimo conteggio.


.. scusa non ho tempo di mostrare l'SQL che verrebbe utilizzato (il mio SQL è arrugginito). Se qualcuno vuole modificare la mia risposta per aggiungere SQL, sarebbe fantastico!
ToolmakerSteve

1

Se si dispone di una tipica struttura di tabella con una colonna chiave primaria ad incremento automatico in cui le righe non vengono mai eliminate, il seguente sarà il modo più rapido per determinare il conteggio dei record e dovrebbe funzionare in modo simile nella maggior parte dei database conformi ANSI:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

Lavoro con tabelle MS SQL contenenti miliardi di righe che richiedono tempi di risposta inferiori al secondo per i dati, inclusi i conteggi dei record. Un simile SELECT COUNT (*) richiederebbe alcuni minuti per il confronto.


1
Non del tutto vero: cosa succede se INSERTviene eseguito il rollback di una transazione? Il valore della chiave primaria sarebbe assente, quindi il conteggio dei record effettivi sarebbe inferiore di uno al valore massimo.
Sir Crispalot,

Potrebbero esserci dei vuoti in sequenza. Di solito è il risultato di rollback.
Osa E

In realtà, c'è una modifica di questa risposta che potrebbe essere significativamente più veloce rispetto a count(*), se un fornitore di database non ha sufficientemente ottimizzato count(*): ogni giorno tiene traccia dell'ultimo indice automatico e del conteggio corrispondente, quindi chiedi un conteggio dei record passati. Può anche gestire deletes se aggiungi un trigger all'eliminazione che diminuisce il totale precedente , se ID record eliminato <= l'ultimo indice automatico.
ToolmakerSteve

1

Per il server SQL provare questo

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 

0

seleziona le righe da sysindexes dove id = Object_ID ('TableName') e indid <2


0

Metti un indice su qualche colonna. Ciò dovrebbe consentire all'ottimizzatore di eseguire una scansione completa dei blocchi di indice, anziché una scansione completa della tabella. Ciò ridurrà i costi di IO. Guarda il piano di esecuzione prima e dopo. Quindi misurare il tempo dell'orologio a muro in entrambi i modi.


Se una tabella ha miliardi di righe senza un indice su qualsiasi colonna, allora ci saranno problemi di prestazioni diffusi, ben oltre la necessità espressa nella domanda originale .. ma è bene che tu lo menzioni (non supporre nulla!) :)
ToolmakerSteve

0

Se stai usando Oracle, che ne dici di questo (supponendo che le statistiche della tabella siano aggiornate):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed mostrerà l'ora dell'ultima raccolta delle statistiche.


0

Con PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'

-1

In SQL Server 2016, posso solo controllare le proprietà della tabella e quindi selezionare la scheda "Archiviazione" - questo mi dà il conteggio delle righe, lo spazio su disco utilizzato dalla tabella, lo spazio dell'indice utilizzato ecc.


Stava cercando un database vendor independent solution. Anche questo richiede una GUI e non può essere automatizzato. Inoltre non è più veloce come COUNT (*)
Frieder

-3

Forse un po 'in ritardo, ma questo potrebbe aiutare gli altri per MSSQL

; WITH RecordCount AS (SELECT ROW_NUMBER () OVER (ORDER BY COLUMN_NAME) AS [RowNumber] FROM TABLE_NAME) SELEZIONA MAX (RowNumber) FROM RecordCount


Questo è significativamente PEGGIORE di COUNT (), a meno che non siamo MOLTO fortunati e l'ottimizzatore non riesca a ottimizzarlo su un COUNT () - perché chiederlo a ORDINARE su una colonna casuale?!?
dsz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.