it-swarm.com.de

Der schnellste Weg, um zu überprüfen, ob sich die InnoDB-Tabelle geändert hat

Meine Anwendung ist sehr datenbankintensiv. Derzeit verwende ich MySQL 5.5.19 und verwende MyISAM, bin jedoch dabei, auf InnoDB zu migrieren. Das einzige verbleibende Problem ist die Prüfsummenleistung.

Meine Anwendung macht ungefähr 500-1000 CHECKSUM TABLE Anweisungen pro Sekunde in Spitzenzeiten, da die GUI des Clients die Datenbank ständig nach Änderungen abfragt (es handelt sich um ein Überwachungssystem, das daher sehr reaktionsschnell und schnell sein muss).

Mit MyISAM gibt es Live-Prüfsummen, die bei Tabellenänderungen vorberechnet werden und SEHR schnell sind. In InnoDB gibt es so etwas jedoch nicht. Damit, CHECKSUM TABLE ist sehr langsam.

Ich habe gehofft, die letzte Aktualisierungszeit der Tabelle überprüfen zu können. Leider ist dies auch in InnoDB nicht verfügbar. Ich stecke jetzt fest, weil Tests gezeigt haben, dass die Leistung der Anwendung drastisch abnimmt.

Es gibt einfach zu viele Codezeilen, die die Tabellen aktualisieren. Daher kommt die Implementierung einer Logik in der Anwendung zum Protokollieren von Tabellenänderungen nicht in Frage.

Gibt es eine schnelle Methode, um Änderungen in InnoDB-Tabellen zu erkennen?

22
Jacket

Ich denke, ich habe die Lösung gefunden. Einige Zeit habe ich mir Percona Server angesehen, um meine MySQL-Server zu ersetzen, und jetzt denke ich, dass es dafür einen guten Grund gibt.

Der Percona-Server führt viele neue INFORMATION_SCHEMA-Tabellen wie INNODB_TABLE_STATS ein, die im Standard-MySQL-Server nicht verfügbar sind. Wenn Sie das tun:

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

Sie erhalten die tatsächliche Zeilenanzahl und einen Zähler. Das Offizielle Dokumentation sagt Folgendes zu diesem Feld aus:

Wenn der Wert der geänderten Spalte "Zeilen/16" oder 2000000000 überschreitet, erfolgt die Neuberechnung der Statistik, wenn innodb_stats_auto_update == 1. Wir können die Alterung der Statistik anhand dieses Werts abschätzen.

Dieser Zähler wird also von Zeit zu Zeit umbrochen, aber Sie können eine Prüfsumme aus der Anzahl der Zeilen und dem Zähler erstellen und dann mit jeder Änderung der Tabelle eine eindeutige Prüfsumme erhalten. Z.B.:

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

Ich wollte sowieso meine Server auf Percona-Server aktualisieren, daher ist diese Begrenzung für mich kein Problem. Das Verwalten von Hunderten von Triggern und das Hinzufügen von Feldern zu Tabellen ist für diese Anwendung ein großes Problem, da die Entwicklung sehr spät ist.

Dies ist die Funktion PHP], die ich mir ausgedacht habe, um sicherzustellen, dass Tabellen unabhängig von der verwendeten Engine und dem verwendeten Server einer Prüfsumme unterzogen werden können:

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

Sie können es so verwenden:

// 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")); 

Ich hoffe, dies erspart anderen Menschen, die das gleiche Problem haben, einige Probleme.

3
Jacket

Führen Sie für die Tabelle mydb.mytable die folgende Abfrage aus:

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

Wenn Sie wissen möchten, welche Tabellen sich in den letzten 5 Minuten geändert haben, führen Sie Folgendes aus:

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

Versuche es !!!

UPDATE 2011-12-21 20:04 EDT

Mein Arbeitgeber (DB/Wweb Hosting Company) hat einen Kunden mit 112.000 InnoDB-Tabellen. In Spitzenzeiten ist es sehr schwierig, INFORMATION_SCHEMA.TABLES zu lesen. Ich habe einen alternativen Vorschlag:

Wenn Sie innodb_file_per_table aktiviert haben und alle InnoDB-Tabellen in .ibd Dateien gibt es eine Möglichkeit, den Zeitpunkt der letzten Aktualisierung (bis zur Minute) zu ermitteln.

Führen Sie für die Tabelle mydb.mytable im Betriebssystem die folgenden Schritte aus:

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

Dieser Zeitstempel stammt vom Betriebssystem. Hier kann man nichts falsch machen.

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

Fügen Sie dies zu my.cnf hinzu, starten Sie mysql neu, und alle InnoDB-Tabellen werden schnell aus dem Pufferpool gelöscht.

Um einen Neustart zu vermeiden, führen Sie einfach aus

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

UPDATE 27.06.2013 07:15 EDT

Wenn es darum geht, Datum und Uhrzeit für eine Datei abzurufen, hat ls das --time-style Möglichkeit:

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

Sie können den Zeitstempel der Datei mit UNIX_TIMESTAMP (NOW ()) vergleichen.

15
RolandoMySQLDBA

Sie sollten in dieser Version auf MySQL v5.6 + aktualisieren. Innodb unterstützt auch die Prüfsummentabelle. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

andernfalls wäre die ideale Lösung, wenn Ihr Client nicht ständig nach Ergebnissen fragt, sondern Sie neue und geänderte Daten pushen, wenn und wenn diese verfügbar sind. Es wäre schneller und der Server würde weniger belastet. Wenn Sie eine webbasierte GUI verwenden, sollten Sie sich APE http://ape-project.org/ oder andere ähnliche Projekte ansehen.

1
Gamesh

Wenn Sie hauptsächlich zu einer Tabelle hinzufügen, können Sie AUTO_INCREMENT als Maß für die Aktualität verwenden.

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

Aber ich würde es vorziehen, in Memcached auf eine andere Quelle wie einen Zähler zu verweisen, den Sie jedes Mal erhöhen, wenn Sie etwas in der Datenbank ändern.

1
sanmai

Diese Antwort hat nichts mit MySQL-Datenbankversionen oder -typen zu tun. Ich wollte wissen, ob Update-Anweisungen Änderungen vornehmen UND dies in meinem PHP-Code tun.

  1. Erstellt eine Dummy-Tabelle mit einem Datensatz und einem Feld, die ich abfragen würde, um den Wert von current_timestamp von mysql zu erhalten.

  2. Fügen Sie der zu aktualisierenden Datentabelle ein Zeitstempelfeld hinzu und verwenden Sie die MySQL-Option "ON UPDATE CURRENT_TIMESTAMP".

  3. Verglichen mit # 1 und # 2

Dies wird nicht 100% der Zeit funktionieren, aber für meine Anwendung war es eine einfache und großartige Lösung. Hoffe das hilft jemandem

0
Steve Padgett

Sie könnten versuchen, Folgendes zu tun:

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

Dies gibt eine Zahl zurück, die mit jeder Tabellenaktualisierung zunimmt. Wenn Sie diese verfolgen, können Sie Änderungen erkennen.

Wichtiger Hinweis: Der Wert wird unmittelbar nach einem UPDATE geändert, nicht nach COMMIT. Daher werden die Änderungen möglicherweise nicht angezeigt, wenn die Änderungen in einer anderen Transaktion vorgenommen wurden, die nicht abgeschlossen wurde.

0
Romuald Brunet