मुझे लगता है कि मैंने इसका हल ढूंढ लिया है। कुछ समय से मैं अपने MySQL सर्वर को बदलने के लिए Percona Server को देख रहा था, और अब मुझे लगता है कि इसके लिए एक अच्छा कारण है।
Percona सर्वर INNODB_TABLE_STATS जैसी कई नई INFORMATION_SCHEMA तालिकाएँ प्रस्तुत करता है, जो मानक MySQL सर्वर में उपलब्ध नहीं है। जब तुम करोगे:
SELECT rows, modified FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table'
आपको वास्तविक पंक्ति गणना और एक काउंटर मिलता है। आधिकारिक प्रलेखन इस क्षेत्र के बारे में निम्नलिखित का कहना है:
यदि संशोधित स्तंभ का मान "पंक्तियों / 16" या 2000000000 से अधिक है, तो आँकड़े पुनर्गणना तब की जाती है जब innodb_stats_auto_update == 1. हम इस मूल्य द्वारा आँकड़ों की पुरानीता का अनुमान लगा सकते हैं।
तो यह काउंटर हर एक बार थोड़ी देर में लपेटता है, लेकिन आप पंक्तियों और काउंटर की संख्या का एक चेकसम बना सकते हैं, और फिर तालिका के प्रत्येक संशोधन के साथ आपको एक अनूठा चेकसम प्राप्त होता है। उदाहरण के लिए:
SELECT MD5(CONCAT(rows,'_',modified)) AS checksum FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table';
मैं वैसे भी Percona सर्वर पर अपने सर्वर को अपग्रेड करने जा रहा था, इसलिए यह बाउंडिंग मेरे लिए कोई समस्या नहीं है। सैकड़ों ट्रिगर्स को प्रबंधित करना और तालिकाओं में फ़ील्ड जोड़ना इस एप्लिकेशन के लिए एक बड़ा दर्द है, क्योंकि विकास में बहुत देर हो चुकी है।
यह PHP फ़ंक्शन है जो मैं यह सुनिश्चित करने के लिए आया हूं कि तालिकाओं को चेक किया जा सकता है जो भी इंजन और सर्वर का उपयोग किया जाता है:
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;
}
आप इसे इस तरह से उपयोग कर सकते हैं:
// 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"));
मुझे आशा है कि इससे अन्य लोगों को भी यही समस्या होने से कुछ परेशानी होगी।