MySQL - Differenza tra l'utilizzo di count (*) e information_schema.tables per il conteggio delle righe


16

Voglio un modo veloce per contare il numero di righe nella mia tabella che ha diversi milioni di righe. Ho trovato il post " MySQL: il modo più veloce per contare il numero di righe " su Stack Overflow, che sembrava risolvere il mio problema. Bayuah ha fornito questa risposta:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

Il che mi è piaciuto perché sembra una ricerca anziché una scansione, quindi dovrebbe essere veloce, ma ho deciso di testarlo

SELECT COUNT(*) FROM table 

per vedere quanta differenza di prestazioni ci fosse.

Purtroppo sto ricevendo risposte diverse come mostrato di seguito:

inserisci qui la descrizione dell'immagine

Domanda

Perché le risposte sono diverse per circa 2 milioni di righe? Immagino che la query che esegue una scansione completa della tabella sia il numero più accurato, ma c'è un modo per ottenere il numero corretto senza dover eseguire questa query lenta?


Ho corso ANALYZE TABLE data_302, completato in 0,05 secondi. Quando ho eseguito nuovamente la query, ora ottengo un risultato molto più vicino di 34384599 righe, ma non è ancora lo stesso numero select count(*)delle righe 34906061. Analizza il ritorno della tabella immediatamente ed elabora in background? Sento che vale la pena ricordare che si tratta di un database di test e al momento non è stato scritto.

A nessuno importa se è solo un caso di dire a qualcuno quanto è grande una tabella, ma volevo passare il conteggio delle righe a un po 'di codice che avrebbe usato quella figura per creare una query asincrona "di uguali dimensioni" per interrogare il database in parallelo, simile al metodo mostrato in Aumentare le prestazioni della query lenta con l'esecuzione della query parallela di Alexander Rubin. Così com'è, otterrò solo l'ID più alto SELECT id from table_name order by id DESC limit 1e spero che i miei tavoli non vengano troppo frammentati.

Risposte:


23

Esistono vari modi per "contare" le righe in una tabella. La cosa migliore dipende dai requisiti (accuratezza del conteggio, frequenza con cui viene eseguita, se abbiamo bisogno del conteggio dell'intera tabella o con variabili wheree group byclausole, ecc.)

  • a) nel modo normale. Contali e basta .

    select count(*) as table_rows from table_name ; 

    Precisione : conteggio accurato al 100% al momento dell'esecuzione della query.
    Efficienza : non va bene per i tavoli grandi. (per le tabelle MyISAM è incredibilmente veloce ma nessuno sta usando MyISAM al giorno d'oggi in quanto presenta così tanti svantaggi su InnoDB. Il "spettacolarmente veloce" si applica anche solo quando si conteggiano le righe di un'intera tabella MyISAM - se la query ha una WHEREcondizione, deve ancora eseguire la scansione della tabella o di un indice.)
    Per le tabelle InnoDB dipende dalle dimensioni della tabella poiché il motore deve eseguire la scansione dell'intera tabella o di un intero indice per ottenere il conteggio accurato. Più grande è il tavolo, più lento diventa.

  • b) utilizzando SQL_CALC_FOUND_ROWSe FOUND_ROWS(). Può essere usato al posto del modo precedente, se vogliamo anche un piccolo numero di righe (cambiando il LIMIT). L'ho visto usato per il paging (per ottenere alcune righe e allo stesso tempo sapere quante sono int totali e calcolare il numero di pgeg).

    select sql_calc_found_rows * from table_name limit 0 ; 
    select found_rows() as table_rows ;

    Precisione : uguale alla precedente.
    Efficienza : uguale alla precedente.

  • c) utilizzando le information_schematabelle, come domanda collegata:

    select  table_rows
    from    information_schema.tables
    where   table_schema = 'database_name'
      and   table_name = 'table_name' ;

    Precisione : solo un'approssimazione. Se la tabella è la destinazione di inserimenti ed eliminazioni frequenti, il risultato può essere molto diverso dal conteggio effettivo. Questo può essere migliorato eseguendolo ANALYZE TABLEpiù spesso.
    Efficienza : molto buona, non tocca affatto il tavolo.

  • d) archiviare il conteggio nel database (in un'altra tabella "contatore" ) e aggiornare quel valore ogni volta che la tabella ha un inserimento, eliminazione o troncamento (ciò può essere ottenuto con i trigger o modificando le procedure di inserimento ed eliminazione) .
    Ciò comporterà ovviamente un ulteriore carico in ogni inserto ed eliminazione ma fornirà un conteggio accurato.

    Precisione : conteggio accurato al 100%.
    Efficienza : molto buona, deve leggere solo una riga da un'altra tabella.
    Mette comunque ulteriore carico nel database.

  • e) memorizzazione ( memorizzazione nella cache ) del conteggio nel livello applicazione e utilizzo del primo metodo (o di una combinazione dei metodi precedenti). Esempio: eseguire la query conteggio esatto ogni 10 minuti. Nel frattempo tra due conteggi, utilizzare il valore memorizzato nella cache.

    Precisione : approssimazione, ma non troppo male in circostanze normali (tranne quando vengono aggiunte o cancellate migliaia di righe).
    Efficienza : ottimo, il valore è sempre disponibile.


1

Perché INNODBvuoi dati information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSprecisi sul conteggio delle righe della tabella, invece di information_schema.TABLES.TABLE_ROWS.

Ho pubblicato maggiori dettagli qui: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843


1
Informazioni errate ... "Per INNODB vuoi informazioni_schema.INNODB_SYS_TABLESTATS.NUM_ROWS per una riga della tabella accurata:" il manuale dice chiaramente stimato sulla NUM_ROWScolonna
Raymond Nijland
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.