本文为您介绍 OceanBase 迁移服务(OceanBase Migration Service,OMS)支持的 ETL 的使用范围和限制。
适用版本
适用于 OMS V3.2.2 及之后版本。
实现原理
OMS 的 ETL 使用了 MySQL 的语法作为输入语法,目前仅支持过滤数据,用户只需要填入过滤数据的条件就可以对全量和增量进行数据过滤。
用户填入的过滤条件会被解析成为由算子组成的语法树。每条记录都会被该语法树中的算子进行计算然后决定是否过滤。
目前支持的运算符如下。
expr 表示算子, [|] 表示正则匹配中选取其中的一个的含义。
一元算子:
针对整形
+expr, -erpr, ~expr, !expr
针对布尔类型
expr NOT TRUE, expr IS TRUE
针对空值比较
expr IS NULL, expr IS NOT NULL
二元算子:
针对布尔类型
expr [AND | OR | XOR] expr
基于整形的算术运算
expr [ & | >> | << | + | - | * | / | % | ^] expr
expr | expr
基于值比较的运算
expr [> | >= | < | <= | = | != | <>] expr
基于布尔值的判定:
BETWEEN expr AND expr
IN (expr, ...., expr)
函数(自定义函数):
CONCAT(expr1, expr2)
IF expr1 == NULL, RETURN expr2
ELSE IF expr2 == null, RETURN expr1
ELSE RETURN expr1 + expr2
也就是如果 expr1 和 expr2 都是 NULL 是会返回 NULL 的。
否则返回非 NULL 的一方或者两方的 CONCAT 值
SUBSTR(expr, exprS (,exprC)?)
SUBSTR(expr, exprS (,exprC)?) 行为等同于数据库的 SUBSTRING 函数
字符串的索引下标从 1 开始, exprS 是开始拷贝字符串的位置, exprC 是拷贝字符串的数目
如果 exprC <= 0 或者 exprS == 0 会返回空串
str = '1234567';
如果 exprS > 0 并且 exprS <= str.length, 那么返回的字符串为
SUBSTRING(str, 1, 2) = '12'
SUBSTRING(str, 1) = '1234567'
SUBSTRING(str, 6, 3) = '67'
SUBSTRING(str, 7, 2) = '7'
如果 exprS > str.length那么返回空串
SUBSTRING(str, 8, 2) = ''
如果 exprS < 0, 并且 -exprS <= str.length, 那么开始位置为 str.length + exprS
SUBSTRING(str, -1, 2) = '7'
SUBSTRING(str, -4, 2) = '45'
SUBSTRING(str, -4) = '4567'
如果 exprS < 0, 并且 -exprS > str.length, 返回空串
REPLACE(exprO, expr1, expr2)
如果 exprO 为 null 返回 null
如果 expr1 为 null 返回 exprO
如果 expr2 为 null,等同于 REPLACE(exprO, expr1, "") 或者 REMOVE(exprO, expr1)
注意事项
不支持类型
不支持 DOUBLE/FLOAT 浮点型数值计算比较,这样可能会造成结果的错误。
关于 NULL 的比较
任何与 NULL 的比较,包括 =, >=, <=, !=, >, < 等都是 FALSE, NULL = NULL 也是 FALSE。
如果要比较 NULL 值应该使用 IS NULL 或者 IS NOT NULL。
关于 CHAR 类型字符串的比较
忽略右空格比较,'abc' = 'abc '。
前置空格不忽略,' abc' != 'abc'。
大小写不忽略,'abc' != 'ABC'。
关于 VARCHAR 类型字符串比较
MySQL 和 DB2 相关的 VARCHAR 比较忽略右空格, 'abc' = 'abc '。
ORACLE VARCHAR 比较不忽略右空格, 'abc' != 'abc '。
AND 和 OR 的优先级
对于没有括号约束的 AND 和 OR 运算符,AND 的优先级高于 OR 的优先级,请使用括号来指定优先级。
列名转换
ETL 不会对用户传入的列的名称进行任何的大小写的转换,请使用转义符 '`' 来转义列名称。
隐式转换
使用 CAST(expr AS type) 进行显式的类型转换,目前支持的类型转换包括:
type = CHARACTER/CHAR 到 VARCHAR_STRING 转换。
type = DEC/NUMERIC/DECIMAL 到 DECIMAL 转换。
type = DOUBLE 到 DOUBLE 转换。
type = SIGNED/UNSIGNED 到 INT64 转换。
type = DATE 到 DATE 转换。
type = TIME 到 TIME 转换。
type = DATETIME 到 DATETIME 转换。
目前支持的隐式转换包括:
INT64 和 DECIMAL 转换到 DECIMAL 比较。
INT64 和 STRING 转换到 INT64 比较。
DECIMAL 和 STRING 转换到 DECIMAL 比较。
对于 MySQL 的 TIMSTAMP 类型可以使用 Linux 时间戳或者 'YYYY-MM-DD HH:MM:SS ZoneID',如果ZoneID没有指定,那么会使用 +08:00 来转换时区。
对于 ORACLE 的 TIMESTAMP WITH LOCAL TIMEZONE 可以使用 'YYYY-MM-DD HH:MM:SS ZoneID' 来进行比较,如果ZoneID没有指定,那么会使用 +08:00 来转换时区。
运行示例
过滤条件: `id` > 100 AND `ts` < '2022-07-11 00:00:00 +08:00'。
INSERT/DELETE id = 1000, ts = '2022-07-10 00:00:00 +08:00' 通过。
INSERT/DELETE id = 99, ts = '2022-07-10 00:00:00 +08:00' 过滤。
UPDATE 更新前 id = 1000, ts = '2022-07-10 00:00:00 +08:00'。
更新后 id = 1000, ts = '2022-07-10 00:00:00 +08:00' 通过。
UPDATE 更新前 id = 99, ts = '2022-07-10 00:00:00 +08:00'。。
更新后 id = 99, ts = '2022-07-10 00:00:00 +08:00' 过滤。
UPDATE 更新前 id = 99, ts = '2022-07-10 00:00:00 +08:00'。
更新后 id = 1000, ts = '2022-07-10 00:00:00 +08:00'。
拆分为 INSERT id = 1000, ts = '2022-07-10 00:00:00 +08:00'。
UPDATE 更新前 id = 1000, ts = '2022-07-10 00:00:00 +08:00'。
更新后 id = 99, ts = '2022-07-10 00:00:00 +08:00'。
拆分为 DELETE id = 1000, ts = '2022-07-10 00:00:00 +08:00'。