首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[MYSQL] mysql checksum table原理浅析并使用python实现

[MYSQL] mysql checksum table原理浅析并使用python实现

原创
作者头像
大大刺猬
发布2024-08-09 16:01:45
发布2024-08-09 16:01:45
52000
代码可运行
举报
文章被收录于专栏:大大刺猬大大刺猬
运行总次数:0
代码可运行

导读

前段时间, 做mysql切换的时候, 使用CHECKSUM TABLE来校验数据一致性. 源端校验时间比目标端多1倍. 而源端的innodb_buffer_pool_size恰好是目标端的1半, 于是就怀疑checksum table和buffer pool有关.

理论上应该是没得关系的, 两边配置(比如IO)等都不一样, 时间有差异也是正常的, 但就巧在这个一半上. 于是我们来稍微研究下.

使用gdb找到关键函数

虽然我们能猜到有check之类的关键词, 但这也直接使用grep -r还是太麻烦了. 我们使用一种通用的方法(之前varchar隐式转换的时候也用过)来找.

代码语言:shell
复制
# 保证mysql只有一个连接

# 使用gdb打断点dispatch_command
(echo -e "break dispatch_command\ncontinue"; 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校验结果是一致的, 说明我们校验方法是正确的

总结

  1. mysql的checksum table是对数据一行行校验的, 也就是和innodb_buffer_pool_size关系不大. (其实直接修改buffer_pool多再校验一次,就能发现时间是一样的, 也能说明没关系的).
  2. checksum和行的读取顺序无关(加法和顺序无关)
  3. checksum列的顺序有关.
  4. checksum和存储引擎关系不大(server层实现的)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 使用gdb找到关键函数
  • mysql_checksum_table
  • 使用python实现checksum table
    • mysql构造数据并校验
    • python 构造数据并校验
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档