|
在 Oracle → MySQL、MariaDB → MySQL、MySQL 跨版本升级等迁移场景中,源端和目标端的数据类型往往不完全一致。过去,gt-checksum 只能依赖内置的默认映射规则,面对复杂的类型差异只能人工逐列核对。gt-checksum v4.0.0 新增 dTypeMappingFile 参数,支持用户自定义数据类型映射规则,让异构迁移校验真正实现"规则驱动"。
dTypeMappingFile 是 gt-checksum v4.0.0 在 checkObject=struct(结构校验)模式下新增的核心参数,用于指定用户自定义的数据类型映射规则文件。
| 参数 | 默认值 | 说明 |
|---|---|---|
dTypeMappingFile | 空(使用内置规则) | 指定 YAML 或 JSON 格式的映射规则文件路径 |
--preview-dtype-mapping | - | CLI 参数,加载规则后输出映射预览表并退出,便于调试验证 |
在配置文件 gc.conf 中添加一行即可启用:
dTypeMappingFile=/path/to/dtype-mapping.yaml
映射规则按迁移场景分组,gt-checksum 会根据源端和目标端的数据库类型及版本自动选择对应的规则组:
| 场景键名 | 适用场景 | 说明 |
|---|---|---|
oracle_to_mysql | Oracle → MySQL 异构迁移 | 处理 NUMBER、VARCHAR2、DATE 等 Oracle 特有类型 |
mysql_upgrade | MySQL 跨版本升级 | 处理 5.6/5.7 → 8.0/8.4 等版本间的类型差异 |
mariadb_to_mysql | MariaDB → MySQL 迁移 | 处理 MariaDB 特有的类型别名和属性差异 |
在真实的迁移项目中,数据类型映射远比"一对一替换"复杂:
场景一:Oracle NUMBER 类型的多义性
Oracle 的 NUMBER 类型是一个"万能数值类型",可以表示整数、定点数、浮点数,取决于 precision 和 scale 的组合:
NUMBER(10,0) → 应映射为 BIGINT(整数)NUMBER(10,2) → 应映射为 DECIMAL(10,2)(定点数)NUMBER(无精度) → 应映射为 DECIMAL 或保持原样不同业务场景对同一个 NUMBER 可能有不同的映射策略,内置规则无法覆盖所有情况。
场景二:MySQL 跨版本的类型漂移
MySQL 5.7 到 8.0 升级过程中,部分类型的默认行为发生了变化(如 utf8mb4 的默认 collation 从 utf8mb4_general_ci 变为 utf8mb4_0900_ai_ci),某些旧类型在新版本中有更合适的替代。升级校验时需要明确告诉工具"这些差异是预期的"。
场景三:MariaDB 到 MySQL 的类型别名
MariaDB 引入了一些类型别名(如 INET6、UUID),这些类型在 MySQL 中并不存在。迁移到 MySQL 时,需要将 INET6 映射为 VARCHAR(39)、UUID 映射为 CHAR(36) 等。虽然 gt-checksum 内置了这些基础映射,但用户可能需要更精细的控制
(如指定 nullable、default 等属性)。
场景四:同名类型的不同属性要求
即使是同一种类型,不同列可能需要不同的属性配置。例如,迁移后的某些列要求 NOT NULL DEFAULT '',而另一些列允许 NULL。这种列级别的精细控制,需要通过自定义规则来实现。
gt-checksum 支持 YAML 和 JSON 两种格式。推荐使用 YAML 格式,可读性更好。
YAML 格式结构
dTypeMapping:
oracle_to_mysql:
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
description: "整数小于等于19位映射为BIGINT"
- source_type: NUMBER
target_type: DECIMAL
description: "其余NUMBER映射为DECIMAL(p,s)"
mariadb_to_mysql:
- source_type: CHAR
target_type: VARCHAR
mysql_upgrade:
- source_type: CHAR
target_type: VARCHAR
顶层键固定为 dTypeMapping,下面按场景分组,每个场景包含一组规则列表。
JSON 格式
{
"dTypeMapping": {
"oracle_to_mysql": [
{"source_type": "NUMBER", "target_type": "BIGINT", "condition": "p <= 19 and s = 0"}
]
}
}
每条规则支持以下字段:
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
source_type | 是 | string | 源端类型名(大小写不敏感),如 NUMBER、VARCHAR2 |
target_type | 是 | string | 目标端类型名,可含精度,如 BIGINT、DECIMAL(10,2) |
condition | 否 | string | 条件表达式,用于精细匹配(见下文) |
object | 否 | string | 对象级匹配模式,支持 schema.*、schema.table、schema.table.column |
column_pattern | 否 | string | 列名正则匹配,如 ^id_、_type$ |
nullable | 否 | bool | 覆盖目标端列的 NULL/NOT NULL 属性 |
unsigned | 否 | bool | 覆盖目标端列的 UNSIGNED 属性(仅数值类型) |
autoinc | 否 | bool | 过滤条件:仅匹配源端列是否具有 AUTO_INCREMENT 属性 |
default | 否 | any | 覆盖目标端列的默认值 |
description | 否 | string | 规则说明(纯文档,不影响匹配逻辑) |
condition 字段支持一个轻量级的条件表达式引擎,用于根据列的精度属性精细匹配。
支持的变量
| 变量 | 含义 | 示例 |
|---|---|---|
p | 精度(Precision) | NUMBER(10,2) 中 p=10 |
s | 小数位(Scale) | NUMBER(10,2) 中 s=2 |
nullable | 是否允许 NULL | 1 表示允许,0 表示不允许 |
unsigned | 是否无符号 | 1 表示 UNSIGNED |
autoinc | 是否自增 | 1 表示 AUTO_INCREMENT |
支持的运算符
=、!=、<、<=、>、>=and(优先级高)、or条件表达式示例
# NUMBER 精度 <= 19 且小数位为 0 → 整数映射为 BIGINT
condition: "p <= 19 and s = 0"
# 精度 > 19 或有小数位 → 映射为 DECIMAL
condition: "p > 19 or s > 0"
# 仅匹配源端为 UNSIGNED 的列
condition: "unsigned = 1"
设计要点:nullable、unsigned、default 是覆盖属性(override),不是过滤条件。也就是说,一条规则不会因为源端列的 nullable 状态不同而不匹配——它匹配后会覆盖目标端的对应属性。如果需要按源端 unsigned 状态过滤,应使用 condition: "unsigned = 1" 而非 unsigned: true。
object 字段支持三个层级的精细匹配,格式为 schema.table.column:
| 格式 | 示例 | 匹配范围 |
|---|---|---|
schema.* | mydb.* | mydb 下所有表的所有列 |
schema.table | mydb.orders | mydb.orders 表的所有列 |
schema.table.column | mydb.orders.order_id | 精确匹配单个列 |
匹配过程大小写不敏感。object 可以与 condition、column_pattern 组合使用,实现多维度的精细控制。
使用示例
mariadb_to_mysql:
# 案例1:schema 级 — sbtest 下所有表的 CHAR 都映射为 VARCHAR
- object: sbtest.*
source_type: CHAR
target_type: VARCHAR
nullable: false
default: ''
# 案例2:表级 — 只映射 sbtest.t9 的 INT 列
- object: sbtest.t9
source_type: INT
target_type: BIGINT
unsigned: true
autoinc: true
# 案例3:列级 — 只映射 sbtest.t9 的 c 列
- source_type: CHAR
target_type: VARCHAR
object: sbtest.t9.c
nullable: false
default: ''
规则采用 first-match(首次匹配)语义:在规则列表中,先定义的规则优先匹配。一旦某条规则匹配成功,后续规则不再检查。
这意味着在编写规则时,更具体的规则应放在前面,更通用的兜底规则放在后面:
oracle_to_mysql:
# 具体规则在前:NUMBER 精度 <= 19 且无小数位 → BIGINT
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
# 通用规则在后:其余 NUMBER → DECIMAL
- source_type: NUMBER
target_type: DECIMAL
如果顺序反过来,所有 NUMBER 类型都会被第一条无条件规则匹配为 DECIMAL,后面的条件规则永远不会生效。
自定义映射规则在两个阶段发挥作用:
比较阶段(Struct Comparison)
在校验源端和目标端的表结构时,gt-checksum 会先根据映射规则将源端列的类型"翻译"为期望的目标端类型,然后再与目标端的实际类型比较。如果目标端的实际类型与映射后的期望类型一致,就认为这是一个"已知可接受的迁移转换",不标记为差异。
修复阶段(Repair SQL Generation)
当检测到结构差异需要生成修复 SQL 时,映射规则中的覆盖属性(nullable、unsigned、autoinc、default)会被写入 ALTER TABLE ... MODIFY COLUMN 语句中,确保修复后的列属性符合预期。
以 Oracle → MySQL 迁移为例,创建 dtype-mapping.yaml:
dTypeMapping:
oracle_to_mysql:
# NUMBER 精度 <= 19 且无小数位 → BIGINT
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
description: "整数 <= 19位映射为BIGINT"
# NUMBER 精度 <= 19 且有小数位 → DECIMAL
- source_type: NUMBER
target_type: DECIMAL
condition: "s > 0"
description: "有小数位的NUMBER映射为DECIMAL(p,s)"
# 其余 NUMBER → DECIMAL(兜底)
- source_type: NUMBER
target_type: DECIMAL
description: "其余NUMBER映射为DECIMAL"
# VARCHAR2 → VARCHAR
- source_type: VARCHAR2
target_type: VARCHAR
description: "VARCHAR2映射为VARCHAR"
# DATE → DATETIME
- source_type: DATE
target_type: DATETIME
description: "Oracle DATE包含时间,映射为DATETIME"
在 gc.conf 中设置:
checkObject=struct
tables=srcdb.*
srcDSN=user:ENC[...]@tcp(10.0.0.1:1521)/orcl
dstDSN=user:ENC[...]@tcp(10.0.0.2:3306)/dstdb
dTypeMappingFile=./dtype-mapping.yaml
使用 --preview-dtype-mapping 参数可以在正式运行前验证规则文件的解析结果:
$ gt-checksum -c gc.conf --preview-dtype-mapping
[dTypeMapping] Scenario: oracle_to_mysql (5 rules)
No. source_type target_type object autoinc condition description
---- -------------------- -------------------- -------------------- -------- ------------------------------ -----------
1 NUMBER BIGINT (any) - p <= 19 and s = 0 整数 <= 19位映射为BIGINT
2 NUMBER DECIMAL (any) - s > 0 有小数位的NUMBER映射为DECIMAL(p,s)
3 NUMBER DECIMAL (any) - (any) 其余NUMBER映射为DECIMAL
4 VARCHAR2 VARCHAR (any) - (any) VARCHAR2映射为VARCHAR
5 DATE DATETIME (any) - (any) Oracle DATE包含时间,映射为DATETIME
预览输出后程序直接退出,不会连接数据库或执行校验,适合在编写规则后快速验证格式和匹配逻辑。
$ gt-checksum -c gc.conf
Initializing gt-checksum
Reading configuration files
Opening log files
Checking configuration options
[STRUCT] Comparing: srcdb.orders ↔ dstdb.orders
[DIFF] srcdb.orders.created_at: source=DATE, dest=DATETIME → covered by dTypeMapping rule #5, skipped
[OK] srcdb.orders.order_id: source=NUMBER(19,0) → BIGINT, dest=BIGINT, matched
[DIFF] srcdb.orders.status: source=VARCHAR2(10), dest=VARCHAR(10) → covered by dTypeMapping rule #4, skipped
[STRUCT] Comparing: srcdb.users ↔ dstdb.users
...
当源端列类型与目标端列类型之间的差异被映射规则覆盖时,gt-checksum 会标记为 covered by dTypeMapping rule,不计入结构差异。
dTypeMapping:
mariadb_to_mysql:
# MariaDB 的 INT AUTO_INCREMENT → MySQL 的 BIGINT
- source_type: INT
target_type: BIGINT
autoinc: true
unsigned: true
nullable: false
description: "自增主键升级为BIGINT"
# MariaDB 的 CHAR → MySQL 的 VARCHAR(schema 级)
- object: mydb.*
source_type: CHAR
target_type: VARCHAR
description: "CHAR统一映射为VARCHAR"
dTypeMapping:
mysql_upgrade:
# MySQL 5.6 的 INT → 8.0 的 BIGINT(仅特定表)
- source_type: INT
target_type: BIGINT
object: mydb.orders
unsigned: true
description: "orders表的INT升级为BIGINT"
# MySQL 5.6 的 CHAR → 8.0 的 VARCHAR
- source_type: CHAR
target_type: VARCHAR
nullable: true
description: "CHAR升级为VARCHAR"
如果不习惯 YAML,也可以使用 JSON 格式:
{
"dTypeMapping": {
"oracle_to_mysql": [
{
"source_type": "NUMBER",
"target_type": "BIGINT",
"condition": "p <= 19 and s = 0",
"description": "整数映射为BIGINT"
},
{
"source_type": "NUMBER",
"target_type": "DECIMAL",
"description": "其余NUMBER映射为DECIMAL"
}
]
}
}
只需将文件扩展名设为 .json,gt-checksum 会自动按 JSON 格式解析。
1. 先预览,再校验
编写完规则文件后,始终先用 --preview-dtype-mapping 验证:
gt-checksum -c gc.conf --preview-dtype-mapping
确认规则数量、匹配顺序和条件表达式无误后,再正式运行校验。
2. 具体规则在前,通用规则在后
由于采用 first-match 语义,必须把精确匹配的规则放在前面:
# 正确:先精确后通用
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
- source_type: NUMBER
target_type: DECIMAL
# 错误:通用规则在前,后面永远不会匹配
- source_type: NUMBER
target_type: DECIMAL
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
<strong>3. 善用 object 实现列级精细控制</strong>
当不同表或列需要不同的映射策略时,使用 object 字段精确指定范围:
# 只对 orders 表的 amount 列应用特殊映射
- source_type: NUMBER
target_type: DECIMAL(20,4)
object: mydb.orders.amount
description: "金额列保留高精度"
<strong>4. 用 description 字段记录映射原因</strong>
description 虽然不影响匹配逻辑,但对于团队协作和后续维护至关重要:
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
description: "业务层确认所有<=19位的NUMBER都是整数ID或计数器,2026-05 张三确认"
<strong>5. 区分 unsigned 过滤与覆盖</strong>
unsigned: true(覆盖属性):匹配成功后,强制目标端列加 UNSIGNED 属性condition: "unsigned = 1"(过滤条件):只匹配源端已经是 UNSIGNED 的列# 只匹配源端 UNSIGNED 的 TINYINT,映射为目标端带 UNSIGNED 的 SMALLINT
- source_type: TINYINT
target_type: SMALLINT
condition: "unsigned = 1"
unsigned: true
6. 为 Oracle NUMBER 编写完整的规则链
Oracle 的 NUMBER 类型覆盖面广,建议至少编写三条规则:
oracle_to_mysql:
- source_type: NUMBER
target_type: BIGINT
condition: "p <= 19 and s = 0"
description: "整数"
- source_type: NUMBER
target_type: DECIMAL
condition: "s > 0"
description: "有小数位"
- source_type: NUMBER
target_type: DECIMAL
description: "兜底"
<strong>1. 仅在 checkObject=struct 模式下生效</strong>
dTypeMappingFile 仅对结构校验模式有效。在 checkObject=data(数据校验)模式下,数据类型映射不影响数据行的比对逻辑。
2. target_type 必须是合法的 MySQL 类型
gt-checksum 启动时会校验每条规则的 target_type 是否在 MySQL 类型白名单中。不合法的类型会输出告警但不会阻止运行。白名单包括:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT、DECIMAL、FLOAT、DOUBLE、CHAR、VARCHAR、BINARY、VARBINARY、TEXT、BLOB、DATE、TIME、DATETIME、TIMESTAMP、ENUM、SET、JSON、BIT 等 30 余种类型。
<strong>3. unsigned 和 autoinc 有类型限制</strong>
unsigned 覆盖属性仅适用于数值类型(TINYINT ~ NUMERIC),对非数值类型设置 unsigned 会被自动忽略并输出告警autoinc 过滤条件仅对整数类型(TINYINT ~ BIGINT)有效,对非整数类型设置 autoinc 会被自动忽略4. 规则加载失败不会阻止程序运行
如果规则文件路径不存在或格式有误,gt-checksum 会输出 WARN 级别日志但继续运行(使用内置默认映射)。建议关注启动日志中的 [WARNING] 输出。
5. 规则全局加载,启动后不可修改
映射规则在程序启动时一次性加载到全局变量 GlobalDTypeMappingRules,运行期间只读。修改规则文件后需要重启 gt-checksum 才能生效。
6. 配置一致性
映射规则应与实际迁移场景匹配。如果配置了 oracle_to_mysql 场景的规则,但实际连接的是两个 MySQL 实例,该场景的规则不会被加载(gt-checksum 会根据源端/目标端的数据库类型自动选择场景)。
gt-checksum v4.0.0 的自定义数据类型映射功能,通过一个结构清晰的 YAML/JSON 配置文件,将异构迁移中的类型对齐工作从"人工逐列核对"升级为"规则驱动自动匹配"。
三种迁移场景(Oracle → MySQL、MySQL 跨版本升级、MariaDB → MySQL)的规则分组设计,配合 schema/table/column 三级对象匹配、条件表达式引擎、以及 nullable/unsigned/autoinc/default 属性覆盖,可以灵活应对从粗粒度到细粒度的
各种映射需求。
--preview-dtype-mapping CLI 参数让规则调试变得直观,first-match 语义让规则优先级清晰可控。
一句话总结:dTypeMappingFile 让异构迁移的类型对齐,从手工活变成了配置活。
相关阅读
gt-checksum v4.0.0 发布:可续跑、可回滚、可审计的数据校验与修复能力全面升级
gt-checksum v4.0.0 新功能解读系列文章(1):断点续传
gt-checksum 使用手册
合作电话:010-64087828
社区邮箱:greatsql@greatdb.com


