[color=red]在主从复制中Checksum常常需要对某些重要的表进行一致性检查。[/color]
Checksum Table在逻辑备份时候前后是否可以[color=red]用于验证数据一致性[/color]。扩展一下发现有一些有趣的问题,[color=red]比如数据插入顺序不同、表引擎不同、操作系统位数不同[/color]等。
[size=large][b]插入顺序不同是否有影响[/b][/size]
我们知道全表扫描是可以有很多种顺序的,尤其当表里面出现过delete动作以后,逻辑导出再导入另外一个表后,[color=red]两个表的全表扫描结果[/color]可能不同。
Checksum table计算返回值的逻辑大致如下:
[color=red] 可以看到只要总行数以及行内容相同,与读取行的顺序无关。[/color]
从这个逻辑还能得到一下几个结论:
1)[color=red]与使用的引擎无关,也就是说即使主备不用同一个引擎[/color],checksum也可用于检查。虽然InnoDB有隐藏行,但这里无视。
2)[color=red]与是否有索引无关。[/color]row_crc只用行本身的数据来计算,[color=blue]并不包括索引数据。[/color]
也就是说如[color=red]果能够保证两个表里面的数据一样,表结构(列内容和顺序一样)[/color],操作系统一样,MySQL版本一致,是能够保证checksum的结果的。
[size=large][b]字段顺序不同是否有影响[/b][/size]
在个row计算row_crc时,[color=red]是每个字段依次计算的。[/color]但计算过程中会将上一个字段的结果作为计算下一个值的输入。
因此[color=red]字段顺序[/color]会影响结果。
[size=large][b]字段长度不同是否有影响[/b][/size]
[color=red]即使看到相同的内容,也有可能得到不同的checksum。[/color]
从上面计算每个field的crc上看,若为变长字段(varchar等),由于用于计算的是实际长度,因此不会影响。[color=blue]比如将表的varchar(20)字段改成varchar(25),不会改变checksum的值。[/color]
[color=red] 但若将char(20)改成char(25),或者int改成bigint,则会改变checksum。[/color]
[size=large][b]操作系统位数不同[/b][/size]
因为返回值是unsigned long,我们就担心32位和64位机器的溢出问题。所幸在计算过程中的ha_myisam直接定义为uint32,只是在返回的时候才转成unsigned long,[color=red]因此无影响[/color]。
[size=large][b]字符集不同[/b][/size]
这个问题其实一直比较含糊。实际上与输入字符集有关。但有一个结论是肯定的:若表里面字段的unhex()值相同,得到的checksum即相同。
[color=red]通过下面的代码进行对表进行检查 返回一个唯一值[/color]
Checksum Table在逻辑备份时候前后是否可以[color=red]用于验证数据一致性[/color]。扩展一下发现有一些有趣的问题,[color=red]比如数据插入顺序不同、表引擎不同、操作系统位数不同[/color]等。
[size=large][b]插入顺序不同是否有影响[/b][/size]
我们知道全表扫描是可以有很多种顺序的,尤其当表里面出现过delete动作以后,逻辑导出再导入另外一个表后,[color=red]两个表的全表扫描结果[/color]可能不同。
Checksum table计算返回值的逻辑大致如下:
ha_checksum crc= 0;
foreach(row in table)
{
row_crc= get_crc(row);
crc+= row_crc;
}
return crc;
[color=red] 可以看到只要总行数以及行内容相同,与读取行的顺序无关。[/color]
从这个逻辑还能得到一下几个结论:
1)[color=red]与使用的引擎无关,也就是说即使主备不用同一个引擎[/color],checksum也可用于检查。虽然InnoDB有隐藏行,但这里无视。
2)[color=red]与是否有索引无关。[/color]row_crc只用行本身的数据来计算,[color=blue]并不包括索引数据。[/color]
也就是说如[color=red]果能够保证两个表里面的数据一样,表结构(列内容和顺序一样)[/color],操作系统一样,MySQL版本一致,是能够保证checksum的结果的。
[size=large][b]字段顺序不同是否有影响[/b][/size]
在个row计算row_crc时,[color=red]是每个字段依次计算的。[/color]但计算过程中会将上一个字段的结果作为计算下一个值的输入。
switch (f->type()) {
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_BIT:
{
String tmp;
f->val_str(&tmp);
row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
tmp.length());
break;
}
default:
row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
break;
}
因此[color=red]字段顺序[/color]会影响结果。
[size=large][b]字段长度不同是否有影响[/b][/size]
[color=red]即使看到相同的内容,也有可能得到不同的checksum。[/color]
从上面计算每个field的crc上看,若为变长字段(varchar等),由于用于计算的是实际长度,因此不会影响。[color=blue]比如将表的varchar(20)字段改成varchar(25),不会改变checksum的值。[/color]
[color=red] 但若将char(20)改成char(25),或者int改成bigint,则会改变checksum。[/color]
[size=large][b]操作系统位数不同[/b][/size]
因为返回值是unsigned long,我们就担心32位和64位机器的溢出问题。所幸在计算过程中的ha_myisam直接定义为uint32,只是在返回的时候才转成unsigned long,[color=red]因此无影响[/color]。
[size=large][b]字符集不同[/b][/size]
这个问题其实一直比较含糊。实际上与输入字符集有关。但有一个结论是肯定的:若表里面字段的unhex()值相同,得到的checksum即相同。
[color=red]通过下面的代码进行对表进行检查 返回一个唯一值[/color]
mysql > checksum table test ;