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、网络、或系统权限错误

    在 Physical Import Mode 下,唯一键/主键的冲突是单独处理的。相关内容将在接下来的章节进行介绍。

    如果 TiDB Lightning 在运行过程中收集到报错的记录,则在退出时会同时在终端和日志中输出各个类型报错数量的统计信息。

    • 输出在终端的报错统计如下表所示:

      1. [2022/03/13 05:33:57.736 +08:00] [WARN] [errormanager.go:459] ["Detect 1000 data type errors in total, please refer to table `lightning_task_info`.`type_error_v1` for more details"]

    所有错误都会写入下游 TiDB 集群 lightning_task_info 数据库中的表中。在导入完成后,如果收集到报错的数据,你可以根据数据库中记录的内容,手动进行处理。

    你可以使用 lightning.task-info-schema-name 配置更改数据库名称。

    1. [lightning]
    2. task-info-schema-name = 'lightning_task_info'

    在此数据库中,TiDB Lightning 创建了 3 个表:

    1. CREATE TABLE syntax_error_v1 (
    2. task_id bigint NOT NULL,
    3. create_time datetime(6) NOT NULL DEFAULT now(6),
    4. table_name varchar(261) NOT NULL,
    5. path varchar(2048) NOT NULL,
    6. offset bigint NOT NULL,
    7. error text NOT NULL,
    8. context text
    9. );
    10. CREATE TABLE type_error_v1 (
    11. task_id bigint NOT NULL,
    12. create_time datetime(6) NOT NULL DEFAULT now(6),
    13. table_name varchar(261) NOT NULL,
    14. path varchar(2048) NOT NULL,
    15. error text NOT NULL,
    16. row_data text NOT NULL
    17. );
    18. task_id bigint NOT NULL,
    19. create_time datetime(6) NOT NULL DEFAULT now(6),
    20. table_name varchar(261) NOT NULL,
    21. index_name varchar(128) NOT NULL,
    22. key_data text NOT NULL,
    23. row_data text NOT NULL,
    24. raw_key mediumblob NOT NULL,
    25. raw_value mediumblob NOT NULL,
    26. raw_handle mediumblob NOT NULL,
    27. raw_row mediumblob NOT NULL,
    28. KEY (task_id, table_name)
    29. );

    type_error_v1 记录由 max-error 配置项管理的所有。每个错误一行。

    conflict_error_v1 记录所有后端中的唯一键/主键冲突,每对冲突有两行。

    列名语法类型冲突说明
    task_id生成此错误的 TiDB Lightning 任务 ID
    create_time记录错误的时间
    table_name包含错误的表的名称,格式为 db.tbl
    path包含错误文件的路径
    offset文件中发现错误的字节位置
    error错误信息
    context围绕错误的文本
    index_name冲突中唯一键的名称。主键冲突为 ‘PRIMARY’
    key_data导致错误的行的格式化键句柄。该内容仅供人参考,机器不可读
    row_data导致错误的格式化行数据。该内容仅供人参考,机器不可读
    raw_key冲突的 KV 对的键
    raw_value冲突的 KV 对的值
    raw_handle冲突行的行句柄
    raw_row冲突行的编码值

    注意

    错误报告记录的是文件偏移量,不是行号或列号,因为行号或列号的获取效率很低。你可以使用下列命令在字节位实现快速跳转(以 183 为例):

    • shell,输出后面几行

      1. tail -c +183 file.csv | head
    • vim::goto 183183go

    在该示例中,我们准备了一个包含一些已知错误的数据源。以下是处理这些错误的具体步骤:

    1. 准备数据库和表结构:

      1. mkdir example && cd example
      2. echo 'CREATE SCHEMA example;' > example-schema-create.sql
      3. echo 'CREATE TABLE t(a TINYINT PRIMARY KEY, b VARCHAR(12) NOT NULL UNIQUE);' > example.t-schema.sql
    2. 准备数据:

      1. cat <<EOF > example.t.1.sql
      2. INSERT INTO t (a, b) VALUES
      3. (0, NULL), -- 列不为空
      4. (1, 'one'),
      5. (2, 'two'),
      6. (40, 'forty'), -- 与下面的 `40` 冲突
      7. (54, 'fifty-four'), -- 与下面的 `'fifty-four'` 冲突
      8. (77, 'seventy-seven'), -- 字符串长度超过 12 个字符
      9. (600, 'six hundred'), -- 数字超出了 TINYINT 数据类型支持的范围
      10. (40, 'forty'), -- 与上面的 `40` 冲突
      11. (42, 'fifty-four'); -- 与上面的 `'fifty-four'` 冲突
    3. 配置 TiDB Lightning,启用严格 SQL 模式,使用 Local 后端模式进行导入,通过删除解决重复项,并最多跳过 10 个错误:

    4. 运行 TiDB Lightning。因为已跳过所有错误,该命令执行完会成功退出:

      1. tiup tidb-lightning -c config.toml
    5. 验证导入的表仅包含两个正常行:

      1. $ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from example.t'
      2. +---+-----+
      3. | a | b |
      4. +---+-----+
      5. | 1 | one |
      6. | 2 | two |
      7. +---+-----+
      1. $ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from lightning_task_info.type_error_v1;' -E
      2. *************************** 1. row ***************************
      3. task_id: 1635888701843303564
      4. create_time: 2021-11-02 21:31:42.620090
      5. table_name: `example`.`t`
      6. path: example.t.1.sql
      7. offset: 46
      8. 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
      9. row_data: (0,NULL)
      10. *************************** 2. row ***************************
      11. task_id: 1635888701843303564
      12. create_time: 2021-11-02 21:31:42.627496
      13. table_name: `example`.`t`
      14. path: example.t.1.sql
      15. offset: 183
      16. 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
      17. row_data: (77,'seventy-seven')
      18. *************************** 3. row ***************************
      19. task_id: 1635888701843303564
      20. create_time: 2021-11-02 21:31:42.629929
      21. table_name: `example`.`t`
      22. path: example.t.1.sql
      23. offset: 253
      24. error: failed to cast value as tinyint(4) for column `a` (#1): [types:1690]constant 600 overflows tinyint
    6. 检查 表是否捕获了具有唯一键/主键冲突的四行: