আমি মনে করি আমি সমাধানটি খুঁজে পেয়েছি। কিছু সময়ের জন্য আমি আমার মাইএসকিউএল সার্ভারগুলি প্রতিস্থাপনের জন্য পারকোনা সার্ভারের দিকে চেয়ে ছিলাম এবং এখন আমি মনে করি এটির পক্ষে যুক্তিসঙ্গত কারণ রয়েছে।
পারকোনা সার্ভার INNODB_TABLE_STATS এর মতো অনেকগুলি নতুন INFORMATION_SCHEMA টেবিল প্রবর্তন করে, যা স্ট্যান্ডার্ড মাইএসকিউএল সার্ভারে উপলভ্য নয়। যখন তুমি কর:
SELECT rows, modified FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table'
আপনি আসল সারি গণনা এবং একটি কাউন্টার পান। অফিসিয়াল ডকুমেন্টেশন এই ক্ষেত্র সম্পর্কে নিম্নলিখিত বলেছেন:
পরিবর্তিত কলামের মান যদি "সারি / 16" বা 2000000000 ছাড়িয়ে যায়, তবে ইনডোডব_স্ট্যাটস_আউটো_আপডেট == ১. যখন আমরা এই মান দ্বারা পরিসংখ্যানের প্রাচীনতা অনুমান করতে পারি তখন পরিসংখ্যান পুনর্নির্মাণ করা হয়।
সুতরাং এই কাউন্টারটি একবারে একবারে psেকে দেয় তবে আপনি সারিগুলির সংখ্যা এবং কাউন্টারটির একটি চেকসাম তৈরি করতে পারেন এবং তারপরে সারণির প্রতিটি সংশোধন করে আপনি একটি অনন্য চেকসাম পাবেন। উদাহরণ:
SELECT MD5(CONCAT(rows,'_',modified)) AS checksum FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table';
আমি যাইহোক যাইহোক আমার সার্ভারগুলি পেরকোনা সার্ভারে আপগ্রেড করতে যাচ্ছি তাই এই সীমাবদ্ধতা আমার পক্ষে কোনও সমস্যা নয়। শত শত ট্রিগার পরিচালনা করা এবং টেবিলগুলিতে ক্ষেত্রগুলি যুক্ত করা এই অ্যাপ্লিকেশনটির জন্য একটি বড় ব্যথা, কারণ এটি বিকাশে খুব দেরী।
ইঞ্জিন এবং সার্ভার যা ব্যবহার করা হোক না কেন টেবিলগুলি চেকসামড করা যায় তা নিশ্চিত করার জন্য এটি আমি এই পিএইচপি ফাংশন নিয়ে এসেছি:
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"));
আমি আশা করি এটি একই সমস্যাযুক্ত অন্যান্য ব্যক্তির জন্য কিছুটা সমস্যা বাঁচায়।