常见问题

本文档旨在帮助用户在使用阿里云数据管理DMS的无锁结构变更功能时,快速诊断和解决遇到的常见报错。通过本指南,您可以了解各类报错的根本原因,并获得清晰的处置建议。

核心解决思路总结

在深入具体问题前,请理解无锁变更的几个核心原则,这有助于您从根本上避免问题:

  • 选择低峰期:无锁变更的本质是“在线数据复制与回放”,源表的高并发写入是导致延迟和失败的最主要原因。因此,尽可能在业务低峰期执行变更是最普适、最有效的解决方案。

  • 排查长事务/大查询:变更的最后一步需要获取表的元数据锁进行切换。任何未提交的长事务或正在运行的大查询都会持有锁,导致变更超时失败。

  • 使用原生DDL作为备选:当表结构(如无主键、有外键/触发器/分区)或DDL操作(如重命名、混合操作)不被无锁变更支持时,最直接的办法是临时关闭实例的“无锁结构变更”选项,采用原生DDL方式执行。

  • 保持SQL简洁单一:避免在一个DDL语句中执行多种类型的操作(如同时添加UK和修改列),将其拆分为多个独立的DDL语句能显著提高成功率。

常见问题及解决方案

错误类型

原因分析

解决方案

因源表 TPS 大,DMS 增量回放延迟过高,表变更失败
(提示:请尽量在业务低峰期重试)

  • 非低峰期执行变更

  • 原表 DML 频繁,DMS 追不上

  • 增量校验引发锁冲突,加剧延迟

  • 实例整体 Binlog 量过大(如其他表 DML 多或拷贝产生大量日志),DMS 订阅带宽打满

  • 在业务低峰期重试

  • 若仍失败,放弃无锁变更,改用原生 DDL

  • 可通过页面降低数据校验比例

  • 放慢原表拷贝速度或更换时间重试

无法获取原表上的 MDL 锁(已尝试 5 次)

原表存在大事务、长查询、悬挂事务等,阻塞 DMS 获取元数据锁

  • 低峰期重试

  • 排查并终止阻塞的大事务/长查询

Lock wait timeout exceeded; try restarting transaction

原表在对一个数据区间进行拷贝的时候,会对拷贝的目标区间增加一个共享的读锁,如果刚好原表区间有一个未提交事务或者悬挂事务等,会导致读锁添加失败,进而任务中断。

  • 低峰期重试

  • 排查并清理阻塞事务

未支持 - 不支持不包含 [主键/唯一索引] 的变更!

表无主键(PK)或唯一索引(UK),DMS 无锁变更依赖 PK/UK

关闭实例“无锁结构变更”选项,改用原生 DDL 执行

任务终止 - 直接执行 DDL 失败!Lock wait timeout exceeded; still fail after retry 6th

原生 DDL 尝试 6 次仍未获取到锁,通常因大事务/长查询/悬挂事务

  • 低峰期重试

  • 排查并处理阻塞源

未支持 - 必须开启 PolarDB 的 Binlog 服务!

PolarDB 实例未开启 Binlog

按文档开启Binlog功能

任务终止 - [数据校验失败]

原因:DMS执行时,数据校验模块发现数据不一致,进而中断了任务。可能的原因:

  1. 用户原因:

    1. 用户进行了非兼容变更,导致数据发生转换或者进度产生变化。

    2. 频繁的DML,比如同一个UK频繁新增、删除、新增、删除,或者更新

  2. DMS原因:某些跨类型不支持,或者程序存在问题,导致数据发生了变化。

改用原生 DDL 执行

任务终止 - 直接执行DDL失败!Statement cancelled due to client request

用户主动中断了原生 DDL 执行

重新发起任务(建议低峰期)

未支持 - 不支持包含主表外键的变更!请暂时先关闭实例上的无锁结构变更选项,采用原生DDL执行。

表上存在外键或触发器

关闭“无锁结构变更”,改用原生 DDL

未支持 - 不支持包含从表外键的变更!请暂时先关闭实例上的无锁结构变更选项,采用原生DDL执行。

未支持 - 不支持包含触发器的变更!请暂时先关闭实例上的无锁结构变更选项,采用原生DDL执行。

任务终止 - ALTER 后的目标表没有相同的主键信息!

DDL 删除了原表的主键或唯一索引

改用原生 DDL 执行

暂时不支持 Unique Key 与其他操作混合的 DDL

由于增加UK一定不能采用DMS无锁变更执行,所以DMS会降级采用原生无锁执行。但DDL中增加UK和其他原生无锁无法执行的SQL混合在一起了,导致最终任何一种方式都无法无锁执行。

拆分为两条 DDL:
1. 执行非 UK 变更
2. 单独执行 ADD UNIQUE KEY

Init Ghost table fail: Specified key was too long (>767 bytes)

索引字段长度超过 InnoDB 限制(767 字节)

修改 DDL,使用前缀索引(如 KEY(col(255))

Specified key was too long; max key length is 767 bytes

Data truncation: Invalid use of NULL value

DDL 语句逻辑错误(如 NOT NULL 列设默认 NULL)

修正 DDL 语法

Access denied; you need (at least one of) the SUPER, REPLICATION CLIENT privilege(s) for this operation

DMS 使用账号权限不足

授予 SUPER 或 REPLICATION CLIENT 权限,或使用高权限账号

未支持 - 仅支持ROW格式日志,请开启BinlogROW模式后再重试。

Binlog格式不对,未开启ROW模式,可能是MIXED模式。

开启ROW模式后,建议KILL老连接,或者重启/切换实例以达到KILL老连接的目的。因为写入binlog格式是会话级别的配置,全局切换到ROW模式,老连接仍然还是MIXED模式,binlog中还可能出现MIXED格式的日志,引起变更失败。

Binlog订阅链路中断(可能原因:回放延迟过高),请低峰期重试!底层报错:不支持, Binlog中识别到非ROW格式的DML SQL: <SQL片段>

实例全局配置已经是ROW模式,但是仍然有MIXED格式的会话在往binlog中写入DML变更日志,不满足DMS无锁结构变更要求,进而引起任务中断。

避免MIXED格式的DML变更日志写入binlog中,DMS仅支持ROW格式的日志。

任务终止 - Alter后的UK包含可以为NULL的列,此类索引会导致脏数据产生!请暂时先关闭实例上的无锁结构变更选项,采用原生DDL执行。

DMS 要求 UK/PK 字段非空,否则可能产生脏数据

改用原生 DDL 执行,或修改 UK 定义为 NOT NULL

id 是自增列,但存在id=0的数据

MySQL 允许 id=0(不推荐),DMS 无锁变更可能丢失该数据

改用原生 DDL,或清理 id=0 的数据

未支持 - 不支持 ALTER TABLE 同时 RENAME 表

DMS 不支持 rename 与其他变更混合

拆分 DDL:先 rename,再 alter(或反之)

未支持 - 当前增量中存在无法执行的UK/PK变更!请暂时先关闭实例上的无锁结构变更选项,采用原生DDL执行。

DMS无锁变更依赖的主键或者UK的值发生了更新,一般有几种情况:

  1. 用户自己或者程序主动update

  2. 用户的程序有特殊的使用语法,都会导致主键更新

    1. replace into

    2. insert on duplicate key

改用原生 DDL 执行

DMS 不支持表分区变更
(新增/修改/删除分区)

分区操作不在 DMS 无锁支持范围内

改用原生 DDL 执行

任务终止 - Init Ghost table fail. msg:Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

用户SQL问题

修正 SQL

Duplicate key name 'xxx'

任务终止 - Init Ghost table fail. msg:Index column size too large. The maximum column size is 767 bytes.

任务终止 - Init Ghost table fail. msg:Specified key was too long; max key length is 3072 bytes

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1