震惊!MySQL 和 TiDB 居然有这种行为不一样!
作者: 这里介绍不了我原文来源:https://tidb.net/blog/f6691ac4
DM 作为一款便携的数据迁移工具,在 MySQL 到 TiDB 的全量数据迁移和增量数据同步中起着很大作用。但由于 MySQL 和 TiDB 并不是完全兼容,所以就可能导致同一条语句在 MySQL 和 TiDB 的执行表现并不一样。
一、万事皆有源
当前架构:上游为 MySQL(一主多从),通过 DM 将部分表同步到下游 TiDB 。用户会提交工单到上游的 MySQL,当然 TiDB 目前并不兼容 MySQL 支持的所有 DDL 语句,这就有可能导致我们的 DM 同步中断。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/DM-1717569455544.png)
现象描述,用户提交 DDL 工单变更字段长度:
alter table table_xxx modify column_xxx varchar(5000) default “ not null comment ‘xxx’。
MySQL 执行正常,但是该语句在 TiDB 执行报错:
“RawCause”: “Error 1265: Data truncated for column ‘xxx’ at row 1”。
根据报错,最先想到的就是查阅文档寻找解决办法,在官方文档搜到如下结果:
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-195-1717569484045.png)
但并不是这个原因造成的,咱们继续往下看。
二、分析解谜
冷静下来去看,其实除了将字段长度增加了,还有将 DEFAULT NULL 改成了 DEFAULT “ NOT NULL ,真让人百思不得其解。
下面我们拿一张表分别在 MySQL 和 TiDB 中去做个测试:
MySQL
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-197-1717569595468.png)
TiDB
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-196-1717569607155.png)
插入数据
MySQL
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-200-1717569651848.png)
TiDB
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-201-1717569662435.png)
执行 DDL
SQL_MODE MySQL 和 TiDB 保持一致,均为 NO_ENGINE_SUBSTITUTION 模式。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-203-1717569682829.png)
MySQL
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-205-1717569706515.png)
TiDB
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-204-1717569721268.png)
到这里我们看到,同样的一条 DDL 语句在 MySQL 和 TiDB 中表现是不一样的。MySQL 执行成功了,但是 TiDB 执行失败了。
解决:更新 null 为 “
解决上述问题其实也比较容易,只需要对我们 C1 列为 null 的记录更新为 “ 即可。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-207-1717569747863.png)
修复 DM 同步
知道了上面的原因,我们可以暂时跳过该 DDL 语句恢复 DM 同步,让业务正常运行。
找到 DDL 的下一个 position
我们的 task-mode 任务模式为 incremental 增量复制,且 enable-gtid 为 false,所以保险的方法我们首先要去寻找 DDL 的下一个位点。
首先根据查询 DM 任务状态我们看到了该 DDL 开始位点和结束位点:
“Message”: “startLocation: [position: (mysql-bin-178-3306.006725, 427465068), gtid-set: ], endLocation: [position: (mysql-bin-178-3306.006725, 427465258)
根据信息解析上游 MySQL 对应的 binlog 文件:
mysqlbinlog –no-defaults –base64-output=decode-rows –start-position=427465068 ./mysql-bin-178-3306.006725 > tmp.sql
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-202-1717569848568.png)
清除元信息,指定位点启动任务
将上述我们找到的位点修改到配置文件中:
除此之外我们还需要清除元信息,启动命令加上 –remove-meta,其目的就是让我们跳过出错的 DDL ,快速恢复业务。
与业务沟通,将现有 null 值改为 “
经过上述测试,在 TiDB 中若字段值为 NULL,想将字段 DEFAULT NULL 改成 DEFAULT “ NOT NULL,那就需要我们先停止任务,记录点位,并在下游 TiDB 执行 update tablename set 列名 where 列名 is NULL。
更改下游 TiDB 表结构
这里我们要修复表结构,执行 DDL 工单的语句即可。
operate-schema 更改 DM 中的表结构
现在我们上下游的表结构都是最新的,但是 DM 内部维护的表结构还需要我们使用 operate-schema 进行修改设置(DM v6.0 之后可使用 binlog-schema 命令):
恢复任务
进行完上述操作后,上游、下游、DM 内部的表结构已经是一致的,我们恢复任务即可。
三、回顾和展望
上述章节主要描述了在使用 DM 过程中发现的问题,以及如何进行解决,当然可能还有更好的解决办法,也欢迎各位大佬指导。
同时我们也知道,TiDB 和 MySQL 在一些 DDL 的执行上还不是完全兼容。但是通过处理该问题并进行梳理形成总结,可以为日后处理其他相似的情况提供良好的思路进行借鉴。
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/413cfdd16080181728e2fef0f】。文章转载请联系作者。
评论