Ich denke, ich habe die Lösung gefunden. Ich habe eine Zeit lang nach Percona Server gesucht, um meine MySQL-Server zu ersetzen, und jetzt glaube ich, dass es einen guten Grund dafür gibt.
Percona Server führt viele neue INFORMATION_SCHEMA-Tabellen wie INNODB_TABLE_STATS ein, die in Standard-MySQL-Servern 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 Zeilenzahl und einen Zähler. In der offiziellen Dokumentation heißt es zu diesem Feld:
Wenn der Wert der geänderten Spalte "Zeilen / 16" oder 2000000000 überschreitet, wird die Statistik neu berechnet, wenn innodb_stats_auto_update == 1. Wir können die Alterung der Statistik anhand dieses Werts schätzen.
Dieser Zähler wird also von Zeit zu Zeit umgebrochen. Sie können jedoch eine Prüfsumme aus der Anzahl der Zeilen und dem Zähler erstellen. Bei jeder Änderung der Tabelle erhalten Sie eine eindeutige Prüfsumme. 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 upgraden, sodass diese Einschränkung für mich kein Problem darstellt. 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 PHP-Funktion, die ich entwickelt habe, um sicherzustellen, dass Tabellen unabhängig von der verwendeten Engine und dem verwendeten Server mit Prüfsummen versehen 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;
}
Du kannst es so benutzen:
// 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 Schwierigkeiten.