it-swarm.it

Il modo più veloce per verificare se la tabella InnoDB è cambiata

La mia applicazione richiede molto database. Attualmente eseguo MySQL 5.5.19 e utilizzo MyISAM, ma sto eseguendo la migrazione a InnoDB. L'unico problema rimasto è la prestazione di checksum.

La mia applicazione fa circa 500-1000 CHECKSUM TABLE istruzioni al secondo nelle ore di punta, perché la GUI del client esegue costantemente il polling del database per le modifiche (è un sistema di monitoraggio, quindi deve essere molto reattivo e veloce).

Con MyISAM, ci sono checksum live che sono precalcolati sulla modifica della tabella e sono MOLTO veloci. Tuttavia, InnoDB non esiste nulla di simile. Così, CHECKSUM TABLE è MOLTO lento.

Spero di essere in grado di controllare l'ultimo tempo di aggiornamento della tabella, purtroppo neanche questo è disponibile in InnoDB. Sono bloccato ora, perché i test hanno dimostrato che le prestazioni dell'applicazione calano drasticamente.

Esistono semplicemente troppe righe di codice che aggiornano le tabelle, quindi l'implementazione della logica nell'applicazione per registrare le modifiche alla tabella è fuori discussione.

Esiste un metodo rapido per rilevare le modifiche nelle tabelle InnoDB?

22
Jacket

Penso di aver trovato la soluzione. Da qualche tempo stavo guardando Percona Server per sostituire i miei server MySQL, e ora penso che ci sia una buona ragione per questo.

Il server Percona introduce molte nuove tabelle INFORMATION_SCHEMA come INNODB_TABLE_STATS, che non è disponibile nel server MySQL standard. Quando lo fai:

SELECT rows, modified FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table'

Ottieni il conteggio delle righe e un contatore. Documentazione ufficiale dice quanto segue su questo campo:

Se il valore della colonna modificata supera "righe/16" o 2000000000, il ricalcolo delle statistiche viene eseguito quando innodb_stats_auto_update == 1. Possiamo stimare la vecchiaia delle statistiche con questo valore.

Quindi questo contatore si avvolge di tanto in tanto, ma puoi fare un checksum del numero di righe e del contatore, e quindi ad ogni modifica della tabella ottieni un checksum unico. Per esempio.:

SELECT MD5(CONCAT(rows,'_',modified)) AS checksum FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table';

Avrei comunque aggiornato i miei server al server Percona, quindi questo limite non è un problema per me. La gestione di centinaia di trigger e l'aggiunta di campi alle tabelle è un grosso problema per questa applicazione, poiché è in fase di sviluppo molto tardi.

Questa è la PHP che ho creato per assicurarsi che le tabelle possano essere verificate indipendentemente dal motore e dal server utilizzati:

function checksum_table($input_tables){
    if(!$input_tables) return false; // Sanity check
    $tables = (is_array($input_tables)) ? $input_tables : array($input_tables); // Make $tables always an array
    $where = "";
    $checksum = "";
    $found_tables = array();
    $tables_indexed = array();
    foreach($tables as $table_name){
        $tables_indexed[$table_name] = true; // Indexed array for faster searching
        if(strstr($table_name,".")){ // If we are passing db.table_name
            $table_name_split = explode(".",$table_name);
            $where .= "(table_schema='".$table_name_split[0]."' AND table_name='".$table_name_split[1]."') OR ";
        }else{
            $where .= "(table_schema=DATABASE() AND table_name='".$table_name."') OR ";
        }
    }
    if($where != ""){ // Sanity check
        $where = substr($where,0,-4); // Remove the last "OR"
        $get_chksum = mysql_query("SELECT table_schema, table_name, rows, modified FROM information_schema.innodb_table_stats WHERE ".$where);
        while($row = mysql_fetch_assoc($get_chksum)){
            if($tables_indexed[$row[table_name]]){ // Not entirely foolproof, but saves some queries like "SELECT DATABASE()" to find out the current database
                $found_tables[$row[table_name]] = true;
            }elseif($tables_indexed[$row[table_schema].".".$row[table_name]]){
                $found_tables[$row[table_schema].".".$row[table_name]] = true;
            }
            $checksum .= "_".$row[rows]."_".$row[modified]."_";
        }
    }

    foreach($tables as $table_name){
        if(!$found_tables[$table_name]){ // Table is not found in information_schema.innodb_table_stats (Probably not InnoDB table or not using Percona Server)
            $get_chksum = mysql_query("CHECKSUM TABLE ".$table_name); // Checksuming the old-fashioned way
            $chksum = mysql_fetch_assoc($get_chksum);
            $checksum .= "_".$chksum[Checksum]."_";
        }
    }

    $checksum = sprintf("%s",crc32($checksum)); // Using crc32 because it's faster than md5(). Must be returned as string to prevent PHPs signed integer problems.

    return $checksum;
}

Puoi usarlo in questo modo:

// checksum a signle table in the current db
$checksum = checksum_table("test_table");

// checksum a signle table in db other than the current
$checksum = checksum_table("other_db.test_table");

// checksum multiple tables at once. It's faster when using Percona server, because all tables are checksummed via one select.
$checksum = checksum_table(array("test_table, "other_db.test_table")); 

Spero che questo risparmi qualche problema ad altre persone che hanno lo stesso problema.

3
Jacket

Per la tabella mydb.mytable, eseguire questa query:

SELECT update_time
FROM information_schema.tables
WHERE table_schema='mydb'
AND table_name='mytable';

Se vuoi sapere quali tabelle sono state modificate negli ultimi 5 minuti, esegui questo:

SELECT table_schema,table_name,update_time
FROM information_schema.tables
WHERE update_time > (NOW() - INTERVAL 5 MINUTE);

Provaci !!!

AGGIORNAMENTO 2011-12-21 20:04 EDT

Il mio datore di lavoro (DB/Wweb hosting comany) ha un client con 112.000 tabelle InnoDB. È molto difficile leggere INFORMATION_SCHEMA.TABLES nelle ore di punta. Ho un suggerimento alternativo:

Se hai innodb_file_per_table abilitato e tutte le tabelle InnoDB sono archiviate in .ibd file, c'è un modo per accertare l'ora dell'ultimo aggiornamento (fino al minuto).

Per la tabella mydb.mytable, procedi come segue nel sistema operativo:

$ cd /var/lib/mysql/mydb
$ ls -l mytable.ibd | awk '{print $4,$5}'

Questo timestamp proviene dal sistema operativo. Non puoi sbagliare su questo.

AGGIORNAMENTO 2011-12-21 22:04 EDT [mysqld] innodb_max_dirty_pages_pct = 0;

Aggiungilo a my.cnf, riavvia mysql e tutte le tabelle di InnoDB subiranno vampate veloci dal pool di buffer.

Per evitare il riavvio, basta eseguire

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

AGGIORNAMENTO 2013-06-27 07:15 EDT

Quando si tratta di recuperare la data e l'ora di un file, ls ha il --time-style opzione:

$ cd /var/lib/mysql/mydb
$ ls -l --time-style="+%s" mytable.ibd | awk '{print $6}'

È possibile confrontare il timestamp del file con UNIX_TIMESTAMP (NOW ()) .

15
RolandoMySQLDBA

È necessario aggiornare a Mysql v5.6 + in quella versione innodb ha anche il supporto per la tabella di checksum. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

a parte questo, la soluzione ideale sarebbe se il tuo client non eseguisse il polling per il risultato è costantemente, ma invece dove spingevi i dati nuovi e modificati quando e se fossero disponibili. Sarebbe più veloce e meno carico sarebbe sul server. se stai usando una GUI basata sul web, dovresti esaminare APE http://ape-project.org/ o altri progetti simili.

1
Gamesh

Se stai aggiungendo principalmente a una tabella, puoi agganciare AUTO_INCREMENT come misura di aggiornamento.

SELECT `AUTO_INCREMENT` FROM `information_schema`.`tables` 
WHERE `table_schema` = DATABASE() AND `table_name` = 'YOUR_TABLE';

Ma preferirei fare riferimento a una fonte otside come un contatore in Memcached che aumenterai ogni volta che cambi qualcosa nel database.

1
sanmai

Questa risposta non ha nulla a che fare con le versioni o i tipi di database mysql, volevo sapere se le istruzioni di aggiornamento stavano apportando modifiche E farlo nel mio codice php ..

  1. Ho creato una tabella fittizia con un record e un campo su cui interrogare per ottenere il valore del mysql's current_timestamp.

  2. Alla tabella di dati da aggiornare, aggiunto un campo timestamp e utilizzato l'opzione mysql "ON UPDATE CURRENT_TIMESTAMP"

  3. Rispetto al n. 1 e al n. 2

Questo non funzionerà al 100% delle volte, ma per la mia applicazione è stata una soluzione semplice e ottima. Spero che questo aiuti qualcuno

0
Steve Padgett

Potresti provare a fare quanto segue:

SELECT rows_changed
FROM information_schema.table_statistics
WHERE table_schema = 'mydb' AND table_name='mytable';

Ciò restituisce un numero che aumenta con ogni aggiornamento della tabella, tenerne traccia consentirà di rilevare le modifiche.

Nota importante: il valore viene modificato immediatamente dopo un AGGIORNAMENTO, non dopo COMMIT. Quindi potresti non vedere le modifiche se le modifiche sono state apportate all'interno di un'altra transazione che non è stata completata.

0
Romuald Brunet