Hello,
First post here, hope it’s not last
I’m currently using Percona Server 5.5.18-rel23.0-log in production. I have 2 servers in a multi-master mode replication, with application level load ballancing and failover. Each server is doing average of 2000 QPS with peaks of > 30K QPS.
This is top 3 from innotop:
Com_select 178263485 71.80%Com_insert 21950184 8.84% Com_update 17436557 7.02%Com_begin 12200095 4.91%Com_change_db 6586734 2.65%Com_set_option 6449891 2.60%Com_delete 2167565 0.87%Com_replace 1736384 0.70%
The application is a monitoring system, and the reason for the high number of SELECTs is that every client polls the database for changes every second. There are about 100 tables that may change at any time, and the data from them needs to be send to the clients ASAP.
Prior to using Percona Server, I was running standard MySQL with MyISAM tables, so the application was built with that in mind.
The method I was using was MyISAMs Live Checksums (checksum=1 in DDL), and the clients was issuing every second “CHECKSUM TABLE xxxx”, storing the result in a session variable, and then comparing it the next second with the new value. This was VERY fast, because MyISAM stores the checksums and returns them without the need to recalculate.
When i first tried to migrate to InnoDB i was faced with the problem that Innodb doesn’t have live checksums, and this led to performance unacceptable for production as each client (there are about 70 clients online in busy hours and 30-40 in non-working hours) performs CHECKSUM TABLE to 10-20 tables each second. So after a research i found that Percona Server has a table in information_schema called innodb_table_stats. In this table i’ve found that the column “modified” increments when the table is updated. So long story short, now I use Percona Server and instead of CHECKSUM TABLE i’m doing a “SELECT rows, modified FROM information_schema.innodb_table_stats” and then i’m making a checksum of these two. Actually here is the function i’ve come up with (it even has a backwards compatibility part):
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;}
So it seems everything is OK now, but it turned out it’s not. The problem is that the column “modified” is incremented only when doing an update on indexed columns. For example if I have table with 3 columns (id (PK), test1 (INDEX), test2) and do UPDATE test1=‘newvalue’ WHERE id=x the “modified” column for this table in innodb_table_stats increments, but if i do UPDATE test2=‘newvalue’ WHERE id=x it doesn’t increment.
Also doing 1000-1500 SELECTs per second from information_schema seems rather hacky for me, but it works…
And finally the question: Can you recommend a better way to detect a change in any table, without managing hundreds of triggers, or adding “last_udpate” columns. Also the database servers are remote, so any file checking method is out of the question too.
So any suggestions?
Thanks!
P.S. I’ve asked this on Stack Overflow, but i didn’t receive any good help there. Anyway here’s the link - http://stackoverflow.com/questions/8643018/mysql-fastest-way -to-check-if-data-in-innodb-table-has-changed/8643198#864319 8