导读
前段时间, 做mysql切换的时候, 使用CHECKSUM TABLE
来校验数据一致性. 源端校验时间比目标端多1倍. 而源端的innodb_buffer_pool_size
恰好是目标端的1半, 于是就怀疑checksum table和buffer pool有关.
理论上应该是没得关系的, 两边配置(比如IO)等都不一样, 时间有差异也是正常的, 但就巧在这个一半上. 于是我们来稍微研究下.
使用gdb找到关键函数
虽然我们能猜到有check之类的关键词, 但这也直接使用grep -r
还是太麻烦了. 我们使用一种通用的方法(之前varchar隐式转换的时候也用过)来找.
# 保证mysql只有一个连接
# 使用gdb打断点dispatch_command
(echo -e "break dispatch_commandncontinue"; while true;do echo 'step';done) | gdb -p `pidof mysqld` > /tmp/t20240809_dispatch_command.gdb.txt 2>&1
# mysql执行checksum table命令
等返回结果后, 我们就得到了checksum table的完整堆栈信息了. 大概1.8MB, 还是比较少的. 然后我们搜索关键词checksum就能找到对应函数了.(具体的哪行代码都有显示, 非常的方便)
mysql_checksum_table
接着我们直接打开源码(sql/sql_table.cc)分析这个函数即可
该函数比较简单, 我就直接列伪代码了. 不考虑表不存在,null等情况(这null也是一个坑...)
代码语言:c 复制ha_checksum crc = 0;
uchar null_mask = 256 - (1 << t->s->last_null_bit_pos);
for (;;) {
ha_checksum row_crc = 0;
for (uint i = 0; i < t->s->fields; i ) {
checksum_crc32(row_crc, f->field_ptr(), f->pack_length());
}
crc = row_crc;
}
protocol->store((ulonglong)crc)
也就是遍历表的每行数据, 每行数据的每个字段做crc32, 然后再将每行的crc32加起来(&(2**32-1))即可.
checksum_crc32 调用 my_checksum. my_checksum 调用crc32_z (zlib)
使用python实现checksum table
既然我们知道了原理, 那么我们就可以自己来实现checksum了. 结合ibd2sql就能快速(开并发)校验一张表的crc32值了. 但我们不整那么麻烦的. 就使用python简单模拟下即可 - _-
mysql构造数据并校验
代码语言:sql复制create table db1.t20240809(name varchar(200) not null, url varchar(300) not null);
insert into db1.t20240809 values('ddcw','https://github.com/ddcw');
insert into db1.t20240809 values('大大刺猬','https://www.modb.pro/u/17942');
insert into db1.t20240809 values('大大刺猬','https://cloud.tencent.com/developer/user/1130242');
checksum table db1.t20240809 ;
python 构造数据并校验
代码语言:python代码运行次数:0复制import zlib
data = [
['ddcw','https://github.com/ddcw'],
['大大刺猬','https://www.modb.pro/u/17942'],
['大大刺猬','https://cloud.tencent.com/developer/user/1130242']
]
crc32 = 0
for row in data:
row_crc = 0
for col in row:
row_crc = zlib.crc32(col.encode(),row_crc)
crc32 = row_crc
crc32 &= (2**32-1)
print(crc32)
和mysql的CHECKSUM TABLE
校验结果是一致的, 说明我们校验方法是正确的
总结
- mysql的checksum table是对数据一行行校验的, 也就是和innodb_buffer_pool_size关系不大. (其实直接修改buffer_pool多再校验一次,就能发现时间是一样的, 也能说明没关系的).
- checksum和行的读取顺序无关(加法和顺序无关)
- checksum列的顺序有关.
- checksum和存储引擎关系不大(server层实现的)