[MYSQL] mysql怎样单表导入? && 从binlog提取指定表

2024年 3月 1日 27.5k 0

导读

上一篇文章介绍了 并发导入, 但还有一种需求是 只恢复特定的某张表. 比如这张表有坏块啊, 或者其它啥需求, 反正就是要恢复这张表, 但是又没单独备份这张表.
只有 一个定时全备(mysqldump)
那要怎么恢复呢???

分析

上一篇介绍的 mysqldump拆分脚本https://www.modb.pro/doc/125805 还支持 仅拆分出来指定的表, 然后我们再从binlog中解析出指定的表做恢复即可.

也就是说现在 只要从binlog中提取指定的表即可. 但客户环境可能不允许使用 binlog2sql或者my2sql等工具…
没事, binlog文件结构不复杂, 自己写个简单脚本提取指定的Binlog即可. 好在之前有解析过binlog文件: https://www.modb.pro/db/625148

binlog文件提取指定的表

我们指定binlog是由 很多event组成的, 而一个事务由 GTID_EVENT 和众多 ROW_EVENT 再加上XID_EVENT 组成, 而ROW_EVENT 又细分为 DELETE_EVENT, WRITE_EVENT, UPDATE_EVENT. 每个ROW_EVENT还有个TABLE_MAP_EVENT来记录元数据信息, 比如字段类型, 表名等信息 (不包含字段名字)

所以我们只需要解析出这几个EVENT即可. 再加上第一个EVENT描述信息即可.

每个EVENT都由 HEADERPAYLOAD 组成. HEADER结构如下:

对象 大小(bytes) 描述
timestamp 4 event生成时间
event_type 1 event类型
server_id 4 产生这个event的server_id
event_size 4 event大小(含header的19bytes)
log_pos 4 event的结束位置(pos)
flags 2 flags

PAYLOAD的话, 每个EVENT都不一样, 这里只看 TABLE_MAP_EVENT的一部分, 因为本次解析binlog只涉及到这一丢丢

名字 大小(字节) 描述
table_id int 表打开的id, 不是数据库里面的table_id
flags 2 保留字段
database_name_length 可变长度 数据库名长度
database_name 取决于database_name_length 数据库名(以0x00结尾, 这个字节不计算在database_name_length中)
table_name_length 可变长度 表名长度
table_name 取决于table_name_length 表名(以额外的0x00结尾, 就是不在table_name_length的计算中)
column_count 可变长度 多少个字段
column_type_list 取决于column_count list类型, 每个字段的数据类型,用1字节表示(比如3表示int 详情)
暂时用不上其它的

脚本编写思路

简单说一下脚本编写思路, 毕竟每个人的思路都不一样

读取BINLOG文件
如果是 table_map_event
就解析payload, 得到库表名字, 并保存下来
如果 匹配表名成功 则记录该EVENT
如果是 row_event
则匹配刚才的库表信息, 成功则记录下来

如果是GTID_EVENT
直接记录下来, 这是事务的开头

如果是 XID_EVENT
记录下来
判断 记录的event队列长度, 大于等于4 则表示 又成功匹配上的表 则写入新文件
清空event队列
其它EVENT 则跳过(seek)

思路还是比较简单的. 就是匹配.

测试

从mysqldump中拆分出指定的表

使用--database--table 匹配需要的表名信息

python MysqlDumpSplitSQL.py t20240228_alldb.sql --database ibd2sql --table ddcw_alltype_table

然后导入数据库

mysql -h127.0.0.1 -P3314 -p123456 < /root/mysqldump_t20240226/splitByddcw_20240301_084906/dbs/ibd2sql/ddcw_alltype_table.sql

从Binlog提取指定的表

用法和上一个脚本一样
使用--database--table 匹配需要的表名信息

python binlogFtable.py /data/mysql_3314/mysqllog/binlog/m3314.000002 --database ibd2sql --table ddcw_alltype_table

然后导入数据库, 由于带有gtid, 故直接导入数据库会失败, 我们需要使用--skip-gtids来忽略gtid信息

mysqlbinlog --skip-gtids /root/mysqldump_t20240226/BinlogFtableByddcw_20240301_085208/m3314.000002 | mysql -h127.0.0.1 -P3314 -p123456

验证

发现我们解析出来的哪张表数据确实是执行binlog之后的了, 证明这个方法是可行的. (我这里只有一个delete操作, 是为了方面演示, 实际环境可能是一大堆DML操作)

总结

本次 通过拆分 mysqldump导出的数据, 然后提取binlog指定的表, 最后使用mysqlbinlog来解析binlog并导入数据库 来实现单表恢复. 看起来流程还是很麻烦的. 但原理还是简单, 就是匹配指定的表, 然后重新回放.
当然如果又备库的话, 直接从备库导出更方便.

附脚本

mysqldump拆分脚本: https://www.modb.pro/doc/125805
binlog提取指定表脚本:https://www.modb.pro/doc/125819

相关文章

pt-kill工具的使用
pt-ioprofile工具包的使用
数据库管理-第216期 Oracle的高可用-01(20240703)
DBMS_REPAIR EXAMPLE SCRIPT WITH PARTITION
数据库事务的四大特性: ACID 
使用BBED修复损坏的SYSTEM文件头

发布评论