写点什么

震惊!MySQL 和 TiDB 居然有这种行为不一样!

  • 2024-06-28
    北京
  • 本文字数:1813 字

    阅读完需:约 6 分钟

作者: 这里介绍不了我原文来源:https://tidb.net/blog/f6691ac4

DM 作为一款便携的数据迁移工具,在 MySQL 到 TiDB 的全量数据迁移和增量数据同步中起着很大作用。但由于 MySQL 和 TiDB 并不是完全兼容,所以就可能导致同一条语句在 MySQL 和 TiDB 的执行表现并不一样。

一、万事皆有源

当前架构:上游为 MySQL(一主多从),通过 DM 将部分表同步到下游 TiDB 。用户会提交工单到上游的 MySQL,当然 TiDB 目前并不兼容 MySQL 支持的所有 DDL 语句,这就有可能导致我们的 DM 同步中断。



现象描述,用户提交 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”。


根据报错,最先想到的就是查阅文档寻找解决办法,在官方文档搜到如下结果:



但并不是这个原因造成的,咱们继续往下看。

二、分析解谜

冷静下来去看,其实除了将字段长度增加了,还有将 DEFAULT NULL 改成了 DEFAULT “ NOT NULL ,真让人百思不得其解。


下面我们拿一张表分别在 MySQL 和 TiDB 中去做个测试:


CREATE TABLE `test_table` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `c1` varchar(255) DEFAULT NULL,  PRIMARY KEY (`id`));
复制代码


MySQL



TiDB


插入数据

insert into test_table (c1) values(""); insert into test_table (c1) values(NULL); insert into test_table (c1) values("test");
复制代码


MySQL



TiDB


执行 DDL

SQL_MODE MySQL 和 TiDB 保持一致,均为 NO_ENGINE_SUBSTITUTION 模式。



MySQL



TiDB



到这里我们看到,同样的一条 DDL 语句在 MySQL 和 TiDB 中表现是不一样的。MySQL 执行成功了,但是 TiDB 执行失败了。

解决:更新 null 为 “

解决上述问题其实也比较容易,只需要对我们 C1 列为 null 的记录更新为 “ 即可。


修复 DM 同步

知道了上面的原因,我们可以暂时跳过该 DDL 语句恢复 DM 同步,让业务正常运行。


  1. 找到 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



  1. 清除元信息,指定位点启动任务


将上述我们找到的位点修改到配置文件中:


====省略其他配置=====mysql-instances:- source-id: "xxx" meta:                                     binlog-name: mysql-bin-178-3306.006725   binlog-pos: 427465321====省略其他配置=====
复制代码


除此之外我们还需要清除元信息,启动命令加上 –remove-meta,其目的就是让我们跳过出错的 DDL ,快速恢复业务。


tiup dmctl:vx.x.x --master-addr xxx:xxx start-task xxx.yaml --remove-meta
复制代码


  1. 与业务沟通,将现有 null 值改为 “


经过上述测试,在 TiDB 中若字段值为 NULL,想将字段 DEFAULT NULL 改成 DEFAULT “ NOT NULL,那就需要我们先停止任务,记录点位,并在下游 TiDB 执行 update tablename set 列名 where 列名 is NULL。


  1. 更改下游 TiDB 表结构


这里我们要修复表结构,执行 DDL 工单的语句即可。


alter table table_xxx modify column_xxx varchar(5000) default '' not null comment 'xxx'。
复制代码


  1. operate-schema 更改 DM 中的表结构


现在我们上下游的表结构都是最新的,但是 DM 内部维护的表结构还需要我们使用 operate-schema 进行修改设置(DM v6.0 之后可使用 binlog-schema 命令):


tiup dmctl:vx.x.x --master-addr xxx:xxx operate-schema set -s 数据源 任务名 -d 库名 -t 表名 表结构文件
复制代码


  1. 恢复任务


进行完上述操作后,上游、下游、DM 内部的表结构已经是一致的,我们恢复任务即可。

三、回顾和展望

上述章节主要描述了在使用 DM 过程中发现的问题,以及如何进行解决,当然可能还有更好的解决办法,也欢迎各位大佬指导。


同时我们也知道,TiDB 和 MySQL 在一些 DDL 的执行上还不是完全兼容。但是通过处理该问题并进行梳理形成总结,可以为日后处理其他相似的情况提供良好的思路进行借鉴。


发布于: 刚刚阅读数: 4
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
震惊!MySQL 和 TiDB 居然有这种行为不一样!_实践案例_TiDB 社区干货传送门_InfoQ写作社区