TiDB Lightning 错误处理功能
- 要导入的数据有少许错误
- 手动定位错误比较困难
- 如果遇到错误就重启 TiDB Lightning,代价太大
本文介绍了类型错误处理功能 () 和重复问题处理功能 (tikv-importer.duplicate-resolution
) 的使用方法,以及保存这些错误的数据库 (lightning.task-info-schema-name
),并提供了一个示例。
你可以通过修改配置项 lightning.max-error
来增加数据类型相关的容错数量。如果设置为 N,那么 TiDB Lightning 允许数据源中出现 N 个错误,而且会跳过这些错误,一旦超过这个错误数就会退出。默认值为 0,表示不允许出现错误。
这些错误会被记录到数据库中。在导入完成后,你可以查看数据库中的数据,手动进行处理。请参见。
该配置对下列错误有效:
- 无效值。例如:在 INT 列设置了
'Text'
- 数字溢出。例如:在 TINYINT 列设置了 500
- 字符串溢出。例如: 在 VARCHAR(5) 列中设置了
'非常长的文字'
- 零日期时间,如
'0000-00-00'
和'2021-12-00'
- 在 NOT NULL 列中设置了 NULL
- 生成的列表达式求值失败
- 列计数不匹配。行中数值的数量和列的数量不一致
on-duplicate = "error"
时,TiDB 后端的唯一键/主键冲突- 其他 SQL 错误
下列错误是致命错误,不能通过配置 max-error
跳过:
- 原始 CSV、SQL 或者 Parquet 文件中的语法错误,例如未闭合的引号
- I/O、网络、或系统权限错误
在 Local 后端模式下,唯一键/主键的冲突是单独处理的。相关内容将在接下来的章节进行介绍。
Local-backend 模式下,TiDB Lightning 导入数据时先将数据转换成 KV 对数组(KV pairs),然后批量添加到 TiKV 中。与 TiDB-backend 模式不同,TiDB Lightning 在 Local-backend 模式下直到任务结束才会检测重复行。因此,Local-backend 模式下的重复错误不是通过 max-error
进行控制,而是通过 duplicate-resolution
配置项进行控制的。你可以通过配置该参数的行为,来决定如何处理有冲突的数据。
[tikv-importer]
duplicate-resolution = 'none'
- ‘none’:不对重复数据进行检测。如果唯一键或主键冲突确实存在,那么导入的表格里会出现不一致的数据和索引,checksum 检查的时候会失败。
- ‘record’:检测重复数据,但不会对重复数据进行修复。如果唯一键或主键冲突确实存在,那么导入的表格里会出现不一致的数据和索引,checksum 检查的时候会失败。
- ‘remove’:检测重复数据,并且删除全部重复行。导入的表格会保持一致,但是重复的行会被忽略,只能通过手动方式添加回来。
TiDB Lightning 只能检测数据源的重复项,不能解决运行 TiDB Lightning 之前的存量数据的冲突问题。
所有错误都会写入下游 TiDB 集群 lightning_task_info
数据库中的表中。在导入完成后,你可以根据数据库中记录的内容,手动进行处理。
你可以使用 lightning.task-info-schema-name
配置更改数据库名称。
[lightning]
task-info-schema-name = 'lightning_task_info'
在此数据库中,TiDB Lightning 创建了 3 个表:
CREATE TABLE syntax_error_v1 (
task_id bigint NOT NULL,
create_time datetime(6) NOT NULL DEFAULT now(6),
table_name varchar(261) NOT NULL,
path varchar(2048) NOT NULL,
offset bigint NOT NULL,
error text NOT NULL,
context text
);
CREATE TABLE type_error_v1 (
task_id bigint NOT NULL,
create_time datetime(6) NOT NULL DEFAULT now(6),
path varchar(2048) NOT NULL,
offset bigint NOT NULL,
row_data text NOT NULL
);
CREATE TABLE conflict_error_v1 (
task_id bigint NOT NULL,
create_time datetime(6) NOT NULL DEFAULT now(6),
table_name varchar(261) NOT NULL,
index_name varchar(128) NOT NULL,
key_data text NOT NULL,
row_data text NOT NULL,
raw_key mediumblob NOT NULL,
raw_value mediumblob NOT NULL,
raw_handle mediumblob NOT NULL,
raw_row mediumblob NOT NULL,
KEY (task_id, table_name)
);
type_error_v1 记录由 max-error
配置项管理的所有类型错误 (Type error)。每个错误一行。
conflict_error_v1 记录所有。每对冲突有两行。
注意:
错误报告记录的是文件偏移量,不是行号或列号,因为行号或列号的获取效率很低。你可以使用下列命令在字节位实现快速跳转(以 183 为例):
shell:输出前面几行
tail -c +183 file.csv | head
vim:
:goto 183
或183go
在该示例中,我们准备了一个包含一些已知错误的数据源。以下是处理这些错误的具体步骤:
准备数据库和表结构:
mkdir example && cd example
echo 'CREATE SCHEMA example;' > example-schema-create.sql
echo 'CREATE TABLE t(a TINYINT PRIMARY KEY, b VARCHAR(12) NOT NULL UNIQUE);' > example.t-schema.sql
准备数据:
cat <<EOF > example.t.1.sql
INSERT INTO t (a, b) VALUES
(0, NULL), -- 列不为空
(1, 'one'),
(2, 'two'),
(40, 'forty'), -- 与下面的 `40` 冲突
(54, 'fifty-four'), -- 与下面的 `'fifty-four'` 冲突
(77, 'seventy-seven'), -- 字符串长度超过 12 个字符
(600, 'six hundred'), -- 数字超出了 TINYINT 数据类型支持的范围
(40, 'fourty'), -- 与上面的 `40` 冲突
EOF
配置 TiDB Lightning,启用严格 SQL 模式,使用 Local 后端模式进行导入,通过删除解决重复项,并最多跳过 10 个错误:
运行 TiDB Lightning。因为已跳过所有错误,该命令执行完会成功退出:
tiup tidb-lightning -c config.toml
验证导入的表仅包含两个正常行:
$ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from example.t'
+---+-----+
| a | b |
+---+-----+
| 1 | one |
| 2 | two |
+---+-----+
检查
type_error_v1
表是否捕获了涉及类型转换的三行:$ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from lightning_task_info.type_error_v1;' -E
*************************** 1. row ***************************
task_id: 1635888701843303564
create_time: 2021-11-02 21:31:42.620090
table_name: `example`.`t`
path: example.t.1.sql
offset: 46
error: failed to cast value as varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin for column `b` (#2): [table:1048]Column 'b' cannot be null
row_data: (0,NULL)
*************************** 2. row ***************************
task_id: 1635888701843303564
create_time: 2021-11-02 21:31:42.627496
table_name: `example`.`t`
path: example.t.1.sql
offset: 183
error: failed to cast value as varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin for column `b` (#2): [types:1406]Data Too Long, field len 12, data len 13
row_data: (77,'seventy-seven')
*************************** 3. row ***************************
task_id: 1635888701843303564
create_time: 2021-11-02 21:31:42.629929
table_name: `example`.`t`
path: example.t.1.sql
offset: 253
error: failed to cast value as tinyint(4) for column `a` (#1): [types:1690]constant 600 overflows tinyint
检查
conflict_error_v1
表是否捕获了具有唯一键/主键冲突的四行: