MySQL数据归档至TiDB

为提高效率,提问时请尽量提供详细背景信息,问题描述清晰可优先响应。以下信息点请尽量提供:

  • 系统版本 & kernel 版本: CentOS7
  • TiDB 版本:v3.0.3
  • 磁盘型号:普通SSD
  • 集群节点分布:3TiDB,3PD,4TiKV
  • 数据量 & region 数量 & 副本数:数据量4.7T,Region数据50W,3副本
  • 问题描述(我做了什么):

使用pt-archiver将MySQL数据归档至TiDB。该操作已经在v2.4.15稳定运行了较长时间。 升级到V3.0.3后,新增加了一张归档表进行数据归档,发现数据可以同步到归档表中,但是同步的数据不正确,多个字段中的值没有同步过去而使用了默认值,造成了数据丢失。

检查tidb.log发现如下报错:

[WARN] [builtin_string.go:269] [“unexpected Flen value(-1) in CONCAT’s args”] [“arg’s index”=0]

随后经过验证:

1)如果直接将数据归档到MySQL实例,再通过DM同步至TiDB相同的表中,结果同步至TiDB中的数据显示正常。

2)直接使用kettle程序进行数据同步至TiDB,结果也是正常的。

所以怀疑是load data语法造成的问题。

求助官方,是否可以得到解决。

1、建议检查 mysql 和 tidb 的 sql_mode 是否一致。

2、请提供完整的报错日志,以及执行归档使用的 sql 语句。

1、 mysql和tidb的sql_mode是一致的。

2、归档脚本如下:

    /usr/local/bin/pt-archiver 
--source h='192.168.200.1',P='3306',u='xxx',p='xxx',D='jianzhi_crm',t='jz_grab_post',i='idx_create_at' 
--dest h='192.168.200.2',P='4000',u='xxx',p='xxx',D='test',t='jz_grab_post_tmp' 
--check-slave-lag h='192.168.200.3',P='3306',u='xxx',p='xxx' --max-lag 1 --check-interval 10 --charset=UTF8 
--where 'create_at<unix_timestamp(date_sub(now(),interval 7 day))' --progress 2000 
--limit 2000 --txn-size 2000 --bulk-insert --no-delete --sleep 1 --statistics

3、pt-archiver执行过程如下:

SELECT /*!40001 SQL_NO_CACHE */ `id`,`company_name`,`address`,`province_name`,`city_name`,`district_name`,`street_name`,`province_id`,`city_id`,`district_id`,`street_id`,`contact_person`,`mobile`,`email`,`industry_code`,`industry_name`,`title`,`job_type`,`date_start`,`date_end`,`am_time_start`,`am_time_end`,`pm_time_start`,`pm_time_end`,`hire_number`,`gender`,`salary_type`,`salary`,`salary_unit`,`unit_type`,`commission_info`,`working_hours`,`payment_type`,`payment_remark`,`description`,`deadline`,`work_weekday`,`weixin`,`agent_check`,`banned_words_check`,`black_check`,`extract_check`,`source`,`source_ext`,`grab_mashup_id`,`do_status`,`post_id`,`create_at`,`modify_at`,`err_detail`,`age_demand`,`extra`,`operate_type`,`as_status`,`handle_type`,`custmer_id`,`quanzhiidentify`,`ocrmobileidentify`,`pay_type` FROM `jianzhi_crm`.`jz_grab_post` FORCE INDEX(`idx_create_at`) WHERE (create_at<unix_timestamp(date_sub(now(),interval 7 day))) AND ((`create_at` > ?)) ORDER BY `create_at` LIMIT 2000

`LOAD DATA LOCAL INFILE ? INTO TABLE `test`.`jz_grab_post_tmp`CHARACTER SET UTF8(`id`,`company_name`,`address`,`province_name`,`city_name`,`district_name`,`street_name`,`province_id`,`city_id`,`district_id`,`street_id`,`contact_person`,`mobile`,`email`,`industry_code`,`industry_name`,`title`,`job_type`,`date_start`,`date_end`,`am_time_start`,`am_time_end`,`pm_time_start`,`pm_time_end`,`hire_number`,`gender`,`salary_type`,`salary`,`salary_unit`,`unit_type`,`commission_info`,`working_hours`,`payment_type`,`payment_remark`,`description`,`deadline`,`work_weekday`,`weixin`,`agent_check`,`banned_words_check`,`black_check`,`extract_check`,`source`,`source_ext`,`grab_mashup_id`,`do_status`,`post_id`,`create_at`,`modify_at`,`err_detail`,`age_demand`,`extra`,`operate_type`,`as_status`,`handle_type`,`custmer_id`,`quanzhiidentify`,`ocrmobileidentify`,`pay_type`)`

4、tidb.log 如下:

5、源数据:

|id|company_name|address|province_name|city_name|district_name|street_name|province_id|city_id|district_id|street_id|contact_person|mobile|email|industry_code|industry_name|title|job_type|date_start|date_end|am_time_start|am_time_end|pm_time_start|pm_time_end|hire_number|gender|salary_type|salary|salary_unit|unit_type|commission_info|working_hours|payment_type|payment_remark|description|deadline|work_weekday|weixin|agent_check|banned_words_check|black_check|extract_check|source|source_ext|grab_mashup_id|do_status|post_id|create_at|modify_at|err_detail|age_demand|extra|operate_type|as_status|handle_type|custmer_id|quanzhiidentify|ocrmobileidentify|pay_type||
        | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
        |77825067|唐山大易文化发展有限公司|唐山高新区时代星城a座208|河北|唐山|乐亭|不限|12|2|1719|-1|张先生|||0||销售代表|44|19700101|19700124|9:00|18:00|||20|0|0|0|0|1||8|2||工作内容:
        工作内容:辅助销售谈判工作的,底薪4000加600元补助职位要求:要求有较强的沟通能力,会察言观色,有经验的优先考虑无经验的,只要你肯努力,我们可以免费培养工作时间:早上9点到中午12点,下午2点到6点单休法定节假日休息|1970/1/24|0,1,2,3,4,5,6||0|0|0|0|21|0|0|1|0|1568044800|1568044800|#NAME?|{"age_start":"0","age_end":"0"}||0|0|0|0|1|0|网邻通1年||

同步后的数据:

|id|company_name|address|province_name|city_name|district_name|street_name|province_id|city_id|district_id|street_id|contact_person|mobile|email|industry_code|industry_name|title|job_type|date_start|date_end|am_time_start|am_time_end|pm_time_start|pm_time_end|hire_number|gender|salary_type|salary|salary_unit|unit_type|commission_info|working_hours|payment_type|payment_remark|description|deadline|work_weekday|weixin|agent_check|banned_words_check|black_check|extract_check|source|source_ext|grab_mashup_id|do_status|post_id|create_at|modify_at|err_detail|age_demand|extra|operate_type|as_status|handle_type|custmer_id|quanzhiidentify|ocrmobileidentify|pay_type|
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|77825067|唐山大易文化发展有限公司|唐山高新区时代星城a座208|河北|唐山|乐亭|不限|12|2|1719|-1|张先生|||0||销售代表|44|19700101|19700124|9:00|18:00|||20|0|0|0|0|1||8|2||工作内容:|2019/9/18|||0|0|0|0|0|0|0|0|0|0|0||||0|0|0|0|0|0||

通过测试,发现load data local infile操作在导入数据时,如果字段中包含换行符,则导入数据时会出现问题。

具体测试如下:

  1. 创建测试表:

     CREATE TABLE `tmp` (
       `id` int(11) NOT NULL AUTO_INCREMENT,
       `name` varchar(255) NOT NULL DEFAULT '',
       PRIMARY KEY (`id`)
     ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  2. 插入测试数据:

insert into tmp(name) values('工作内容: 【工作时间】')

  1. 导出数据:

select * from test.tmp into outfile '/data/mysql/tmp1.sql';

查看导出的数据: cat /data/mysql/tmp1.sql image

  1. load data 导入数据到tidb:

LOAD DATA LOCAL INFILE ‘/data/mysql/tmp1.sql’ INTO TABLE test.tmp CHARACTER SET UTF8(id,name);

image

注意:导入1行数据时,结果变成了2行,因为换行符造成了数据异常。 image

  1. 同样的数据,load导入到MySQL则是正常的。

这个问题不是 TiDB 语法支持的问题,可以参考 load 对一些特殊字符的识别来处理,比如可以把文件里面的换行符处理掉在 load 进 TiDB 。