Jac*_*ket 5 mysql triggers innodb checksum
我的应用程序非常密集数据库.目前,我正在运行MySQL 5.5.19并使用MyISAM,但我正在迁移到InnoDB.剩下的唯一问题是校验和性能.
我的应用程序在高峰时间每秒执行大约500-1000"CHECKSUM TABLE"语句,因为客户端GUI不断轮询数据库以进行更改(它是一个监视系统,因此必须非常快速响应和快速).
使用MyISAM,有一些Live校验和在表修改时预先计算,并且非常快.但是,InnoDB中没有这样的东西.所以,CHECKSUM TABLE很慢......
我希望能够检查表的最后更新时间,不幸的是,这在InnoDB中也不可用.我现在卡住了,因为测试表明应用程序的性能急剧下降......
有更多的代码行更新表,因此在应用程序中实现逻辑表更改是不可能的......
数据库生态系统由一个主na 3从属组成,因此不能选择本地文件检查.我想到了一种模拟校验和缓存的方法 - 一个包含两列的查找表 - table_name,checksum,并在表中发生更改时更新该表和触发器,但我有大约100个要监视的表,这意味着每个表有3个触发器= 300个触发器.很难维护,我不确定这不会再次成为一次表现.
那么有没有任何FAST方法来检测InnoDB表中的变化?
谢谢!
我想我已经找到了解决方案。一段时间以来,我一直在寻找 Percona Server 来取代我的 MySQL 服务器,现在我认为这是有充分理由的。
\n\nPercona 服务器引入了许多新的 INFORMATION_SCHEMA 表,例如 INNODB_TABLE_STATS,这在标准 MySQL 服务器中不可用。\n当您这样做时:
\n\nSELECT rows, modified FROM information_schema.innodb_table_stats WHERE table_schema=\'db\' AND table_name=\'table\'\nRun Code Online (Sandbox Code Playgroud)\n\n您将获得实际行数和计数器。官方文档对此字段的说明如下:
\n\n\n\n\n如果修改列的值超过 \xe2\x80\x9crows / 16\xe2\x80\x9d 或 2000000000,则当 innodb_stats_auto_update == 1 时\n 会重新计算统计信息。\n 我们可以通过该值估计统计信息的旧度。
\n
因此,该计数器每隔一段时间就会换行一次,但您可以对行数和计数器进行校验和,然后每次修改表时都会获得唯一的校验和。例如:
\n\nSELECT MD5(CONCAT(rows,\'_\',modified)) AS checksum FROM information_schema.innodb_table_stats WHERE table_schema=\'db\' AND table_name=\'table\';\nRun Code Online (Sandbox Code Playgroud)\n\n无论如何,我打算将我的服务器升级到 Percona 服务器,所以这个边界对我来说不是问题。管理数百个触发器并向表添加字段是该应用程序的一大难题,因为它的开发已经很晚了。
\n\n这是我想出的 PHP 函数,以确保无论使用什么引擎和服务器,都可以对表进行校验和:
\n\nfunction checksum_table($input_tables){\n if(!$input_tables) return false; // Sanity check\n $tables = (is_array($input_tables)) ? $input_tables : array($input_tables); // Make $tables always an array\n $where = "";\n $checksum = "";\n $found_tables = array();\n $tables_indexed = array();\n foreach($tables as $table_name){\n $tables_indexed[$table_name] = true; // Indexed array for faster searching\n if(strstr($table_name,".")){ // If we are passing db.table_name\n $table_name_split = explode(".",$table_name);\n $where .= "(table_schema=\'".$table_name_split[0]."\' AND table_name=\'".$table_name_split[1]."\') OR ";\n }else{\n $where .= "(table_schema=DATABASE() AND table_name=\'".$table_name."\') OR ";\n }\n }\n if($where != ""){ // Sanity check\n $where = substr($where,0,-4); // Remove the last "OR"\n $get_chksum = mysql_query("SELECT table_schema, table_name, rows, modified FROM information_schema.innodb_table_stats WHERE ".$where);\n while($row = mysql_fetch_assoc($get_chksum)){\n if($tables_indexed[$row[table_name]]){ // Not entirely foolproof, but saves some queries like "SELECT DATABASE()" to find out the current database\n $found_tables[$row[table_name]] = true;\n }elseif($tables_indexed[$row[table_schema].".".$row[table_name]]){\n $found_tables[$row[table_schema].".".$row[table_name]] = true;\n }\n $checksum .= "_".$row[rows]."_".$row[modified]."_";\n }\n }\n\n foreach($tables as $table_name){\n if(!$found_tables[$table_name]){ // Table is not found in information_schema.innodb_table_stats (Probably not InnoDB table or not using Percona Server)\n $get_chksum = mysql_query("CHECKSUM TABLE ".$table_name); // Checksuming the old-fashioned way\n $chksum = mysql_fetch_assoc($get_chksum);\n $checksum .= "_".$chksum[Checksum]."_";\n }\n }\n\n $checksum = sprintf("%s",crc32($checksum)); // Using crc32 because it\'s faster than md5(). Must be returned as string to prevent PHPs signed integer problems.\n\n return $checksum;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n你可以这样使用它:
\n\n// checksum a signle table in the current db\n$checksum = checksum_table("test_table");\n\n// checksum a signle table in db other than the current\n$checksum = checksum_table("other_db.test_table");\n\n// checksum multiple tables at once. It\'s faster when using Percona server, because all tables are checksummed via one select.\n$checksum = checksum_table(array("test_table, "other_db.test_table")); \nRun Code Online (Sandbox Code Playgroud)\n\n我希望这可以为其他遇到同样问题的人节省一些麻烦。
\n| 归档时间: |
|
| 查看次数: |
6617 次 |
| 最近记录: |