故障解析丨导入字符串NULL导致主从报错

这篇具有很好参考价值的文章主要介绍了故障解析丨导入字符串NULL导致主从报错。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.背景概述

目前需要搭建一个从库,由于单表数据量较大,时间比较有限,考虑到导入导出的时间,并且GreatSQL支持并行load data的功能,能够加速数据的导入,因此决定使用 select into outfile 和 load data 的方式进行数据的迁移;

在数据导入完成后进行数据同步,从库发生报错 1032 找不到记录,但是登录从库中可以查询到此条记录,这里就很奇怪;

最后通过解析relaylog,根据relaylog中的update记录,以每个字段为查询条件进行查询,发现是由于NULL值列导致的,主库这列的值是 NULL,从库在导入后导成了字符串"NULL",因此导致回放update操作时匹配不到数据而报错1032.

2.问题复现

本次测试基于 GreatSQL 8.0.32-24

2.1 初始化2个单机实例

2.2 主节点创建测试表

greatsql> create database test;
greatsql> use test;

greatsql> create table t1 (id int,
name varchar(30),
age int,
addr varchar(30),
school varchar(30),
unique key (id)) engine=innodb;

greatsql> insert into t1 values
(1,'小红',10,'北京','一中'),
(2,'小绿',11,'北京','一中'),
(3,'小黄',12,'北京',NULL),
(4,'小蓝',13,'北京',NULL),
(5,'小黑',14,'北京',NULL);

2.3 查看数据

greatsql> select * from t1;
+----+--------+------+--------+--------+
| id | name  | age  | addr  | school |
+----+--------+------+--------+--------+
|  1 | 小红  |  10 | 北京  | 一中  |
|  2 | 小绿  |  11 | 北京  | 一中  |
|  3 | 小黄  |  12 | 北京  | NULL  |
|  4 | 小蓝  |  13 | 北京  | NULL  |
|  5 | 小黑  |  14 | 北京  | NULL  |
+----+--------+------+--------+--------+
5 rows in set (0.00 sec)

2.4 主节点导出数据

greatsql> select * from test.t1 into outfile '/greatsql/t1.csv' FIELDS TERMINATED BY '|+|'  ESCAPED BY '' LINES TERMINATED BY '/*rowsxxx*/';

2.5 查看导出的数据

$ cat t1.csv 

1|+|小红|+|10|+|北京|+|一中/*rowsxxx*/2|+|小绿|+|11|+|北京|+|一中/*rowsxxx*/3|+|小黄|+|12|+|北京|+|NULL/*rowsxxx*/4|+|小蓝|+|13|+|北京|+|NULL/*rowsxxx*/5|+|小黑|+|14|+|北京|+|NULL/*rowsxxx

可以看到导出的数据中包含 NULL

2.6 从库创建表并导入数据

greatsql> create database test;
use test;
create table t1 (id int,
name varchar(30),
age int,
addr varchar(30),
school varchar(30),
unique key (id)) engine=innodb;

导入数据

greatsql> load data  infile '/greatsql/t1.csv' into table test.t1 fields terminated by '|+|' ESCAPED BY '' lines terminated by '/*rowsxxx*/'; 

2.7 从库查询数据

greatsql> select * from test.t1;
+----+--------+------+--------+--------+
| id | name  | age  | addr  | school |
+----+--------+------+--------+--------+
|  1 | 小红  |  10 | 北京  | 一中  |
|  2 | 小绿  |  11 | 北京  | 一中  |
|  3 | 小黄  |  12 | 北京  | NULL  |
|  4 | 小蓝  |  13 | 北京  | NULL  |
|  5 | 小黑  |  14 | 北京  | NULL  |
+----+--------+------+--------+--------+
5 rows in set (0.00 sec)

2.8 从库建立复制

greatsql> reset master;
Query OK, 0 rows affected (0.04 sec)

greatsql> set global gtid_purged='b94e6517-68dd-11ee-b43b-00163ecb92e3:1-5755';
Query OK, 0 rows affected (0.00 sec)

greatsql> show master status;
+---------------+----------+--------------+------------------+---------------------------------------------+
| File      | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set              |
+---------------+----------+--------------+------------------+---------------------------------------------+
| binlog.000001 |    153 |        |          | b94e6517-68dd-11ee-b43b-00163ecb92e3:1-5755 |
+---------------+----------+--------------+------------------+---------------------------------------------+
1 row in set (0.00 sec)

greatsql> change master to master_user='root',master_password='greatdb',master_host='192.168.137.162',master_port=6001,master_auto_position=1;
Query OK, 0 rows affected, 7 warnings (0.02 sec)

greatsql> start slave;
Query OK, 0 rows affected, 1 warning (0.04 sec)

greatsql> show slave status\G
*************************** 1. row ***************************
        Slave_IO_State: Waiting for source to send event
         Master_Host: 192.168.137.162
         Master_User: root
         Master_Port: 6001
        Connect_Retry: 60
       Master_Log_File: binlog.000002
     Read_Master_Log_Pos: 1861574
        Relay_Log_File: relaylog.000002
        Relay_Log_Pos: 395
    Relay_Master_Log_File: binlog.000002
       Slave_IO_Running: Yes
      Slave_SQL_Running: Yes
       Replicate_Do_DB: 
......

2.9 主库更新数据

greatsql> update test.t1 set name='小小黑' where id=5;

2.10 从库查看复制状态

greatsql> show slave status\G
*************************** 1. row ***************************
        Slave_IO_State: Waiting for source to send event
         Master_Host: 172.17.137.162
         Master_User: root
         Master_Port: 6001
        Connect_Retry: 60
       Master_Log_File: binlog.000002
     Read_Master_Log_Pos: 1863564
        Relay_Log_File: relaylog.000002
        Relay_Log_Pos: 395
    Relay_Master_Log_File: binlog.000002
       Slave_IO_Running: Yes
      Slave_SQL_Running: No
       Replicate_Do_DB: 
     Replicate_Ignore_DB: 
      Replicate_Do_Table: 
    Replicate_Ignore_Table: 
   Replicate_Wild_Do_Table: 
 Replicate_Wild_Ignore_Table: 
          Last_Errno: 1032
          Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'b94e6517-68dd-11ee-b43b-00163ecb92e3:5756' at master log binlog.000002, end_log_pos 1863537. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.
         Skip_Counter: 0
......

greatsql> select * from performance_schema.replication_applier_status_by_worker limit 1\G
*************************** 1. row ***************************
                      CHANNEL_NAME: 
                       WORKER_ID: 1
                       THREAD_ID: NULL
                     SERVICE_STATE: OFF
                   LAST_ERROR_NUMBER: 1032
                   LAST_ERROR_MESSAGE: Worker 1 failed executing transaction 'b94e6517-68dd-11ee-b43b-00163ecb92e3:5756' at master log binlog.000002, end_log_pos 1863537; Could not execute Update_rows event on table test.t1; Can't find record in 't1', Error_code: 1032; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log FIRST, end_log_pos 1863537
                  LAST_ERROR_TIMESTAMP: 2023-10-17 10:02:46.396166
                LAST_APPLIED_TRANSACTION: 
   LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
  LAST_APPLIED_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 0000-00-00 00:00:00.000000
     LAST_APPLIED_TRANSACTION_START_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
      LAST_APPLIED_TRANSACTION_END_APPLY_TIMESTAMP: 0000-00-00 00:00:00.000000
                  APPLYING_TRANSACTION: b94e6517-68dd-11ee-b43b-00163ecb92e3:5756
     APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP: 2023-10-17 10:02:46.392331
    APPLYING_TRANSACTION_IMMEDIATE_COMMIT_TIMESTAMP: 2023-10-17 10:02:46.392331
       APPLYING_TRANSACTION_START_APPLY_TIMESTAMP: 2023-10-17 10:02:46.393814
         LAST_APPLIED_TRANSACTION_RETRIES_COUNT: 0
  LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0
 LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 
LAST_APPLIED_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
           APPLYING_TRANSACTION_RETRIES_COUNT: 0
    APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_NUMBER: 0
   APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_MESSAGE: 
  APPLYING_TRANSACTION_LAST_TRANSIENT_ERROR_TIMESTAMP: 0000-00-00 00:00:00.000000
1 row in set (0.00 sec)

可以看到从库发生1032报错,找不到记录

2.11 解析从库relay log

#231017 10:02:46 server id 1  end_log_pos 1863456 Table_map: `test`.`t1` mapped to number 180
\# has_generated_invisible_primary_key=0
\# at 673
\#231017 10:02:46 server id 1  end_log_pos 1863537 Update_rows: table id 180 flags: STMT_END_F
\### UPDATE `test`.`t1`
\### WHERE
\###  @1=5 /* INT meta=0 nullable=1 is_null=0 */
\###  @2='小黑' /* VARSTRING(120) meta=120 nullable=1 is_null=0 */
\###  @3=14 /* INT meta=0 nullable=1 is_null=0 */
\###  @4='北京' /* VARSTRING(120) meta=120 nullable=1 is_null=0 */
\###  @5=NULL /* VARSTRING(120) meta=120 nullable=1 is_null=1 */
\### SET
\###  @1=5 /* INT meta=0 nullable=1 is_null=0 */
\###  @2='小小黑' /* VARSTRING(120) meta=120 nullable=1 is_null=0 */
\###  @3=14 /* INT meta=0 nullable=1 is_null=0 */
\###  @4='北京' /* VARSTRING(120) meta=120 nullable=1 is_null=0 */
\###  @5=NULL /* VARSTRING(120) meta=120 nullable=1 is_null=1 */
\# at 754
\#231017 10:02:46 server id 1  end_log_pos 1863564 Xid = 5940
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by greatsqlbinlog */ /*!*/;
DELIMITER ;
\# End of log file

故障解析丨导入字符串NULL导致主从报错

可以看到update更新前的数据与从库的数据一致,那么为什么还会报错 找不到记录呢?

2.12 根据relay log中的内容去从库查询数据

greatsql> select * from test.t1 where id=5;
+------+--------+------+--------+--------+
| id  | name  | age  | addr  | school |
+------+--------+------+--------+--------+
|   5 | 小黑  |  14 | 北京  | NULL  |
+------+--------+------+--------+--------+
1 row in set (0.01 sec)

greatsql> select * from test.t1 where name='小黑';
+------+--------+------+--------+--------+
| id  | name  | age  | addr  | school |
+------+--------+------+--------+--------+
|   5 | 小黑  |  14 | 北京  | NULL  |
+------+--------+------+--------+--------+
1 row in set (0.01 sec)

greatsql> select * from test.t1 where age=14;
+------+--------+------+--------+--------+
| id  | name  | age  | addr  | school |
+------+--------+------+--------+--------+
|   5 | 小黑  |  14 | 北京  | NULL  |
+------+--------+------+--------+--------+
1 row in set (0.00 sec)

greatsql> select * from test.t1 where addr='北京';
+------+--------+------+--------+--------+
| id  | name  | age  | addr  | school |
+------+--------+------+--------+--------+
|   1 | 小红  |  10 | 北京  | 一中  |
|   2 | 小绿  |  11 | 北京  | 一中  |
|   3 | 小黄  |  12 | 北京  | NULL  |
|   4 | 小蓝  |  13 | 北京  | NULL  |
|   5 | 小黑  |  14 | 北京  | NULL  |
+------+--------+------+--------+--------+
5 rows in set (0.00 sec)

greatsql> select * from test.t1 where school is null;
Empty set (0.01 sec)

greatsql> select * from test.t1 where school='null';
+------+--------+------+--------+--------+
| id  | name  | age  | addr  | school |
+------+--------+------+--------+--------+
|   3 | 小黄  |  12 | 北京  | NULL  |
|   4 | 小蓝  |  13 | 北京  | NULL  |
|   5 | 小黑  |  14 | 北京  | NULL  |
+------+--------+------+--------+--------+
3 rows in set (0.00 sec)

可以看到,根据null值作为查询条件时,匹配不到数据; 根据字符串"null" 进行匹配是可以匹配到数据

2.13 去主库进行查询

greatsql> select * from test.t1 where school is null;
+------+-----------+------+--------+--------+
| id  | name    | age  | addr  | school |
+------+-----------+------+--------+--------+
|   3 | 小黄    |  12 | 北京  | NULL  |
|   4 | 小蓝    |  13 | 北京  | NULL  |
|   5 | 小小黑   |  14 | 北京  | NULL  |
+------+-----------+------+--------+--------+
3 rows in set (0.00 sec)

greatsql> select * from test.t1 where school='null';
Empty set (0.00 sec)

在主库查询的结果与从库相反

可以得出结论,由于从库导入的数据将NULL值列的数据导入成了字符串 NULL,因此导致主从数据出现了不一致。

2.14 修复从库

greatsql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

greatsql> update test.t1 set school=NULL where school='null';
Query OK, 3 rows affected (0.01 sec)
Rows matched: 3  Changed: 3  Warnings: 0
 
greatsql> start slave;
Query OK, 0 rows affected, 1 warning (0.04 sec)
 
greatsql> show slave status\G
*************************** 1. row ***************************
        Slave_IO_State: Waiting for source to send event
         Master_Host: 172.17.137.162
         Master_User: root
         Master_Port: 6001
        Connect_Retry: 60
       Master_Log_File: binlog.000002
     Read_Master_Log_Pos: 1863564
        Relay_Log_File: relaylog.000003
        Relay_Log_Pos: 435
    Relay_Master_Log_File: binlog.000002
       Slave_IO_Running: Yes
      Slave_SQL_Running: Yes
       Replicate_Do_DB: 
......

可以看到主从状态已经恢复正常

3.总结

1.如果FIELDS ESCAPED BY字符为空字符,则没有字符被转义,并且NULL被作为NULL输出,而不是\N;这也是导致此次主从报错的原因。

2.如果这张表使用的是主键而不是唯一索引,即使某些列被导入为字符串NULL,也不会报错。

3.如果这张表没有索引或有普通索引,则会报错。

Enjoy GreatSQL 😃


关于GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接

GreatSQL社区

Gitee

Github

Bilibili

技术交流群

微信:添加GreatSQL社区助手好友,微信号wanlidbc发送验证信息加群

QQ群:533341697


Enjoy GreatSQL 😃

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

故障解析丨导入字符串NULL导致主从报错

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

故障解析丨导入字符串NULL导致主从报错文章来源地址https://www.toymoban.com/news/detail-751486.html

到了这里,关于故障解析丨导入字符串NULL导致主从报错的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Postman传json字符串,接收时却是null【已解决】

    使用postman发送post请求,在body里带1个json字符串  结果,sql日志打印显示参数都为空。 == Preparing: insert into `order` (user_id,commodity_code,count,money)values (?,?,?,?) == Parameters: null, null, null, null == Updates: 1 首先,如果你的Headers里已经配置好了 application/json格式:   那么,你将json字符串改

    2024年02月09日
    浏览(15)
  • mysql 解析json字符串、数组字符串、json数组字符串

    笔者使用mysql 5.7进行了一次json字符串的解析,因为一直在搞大数据相关的数据库、olap等,太久没有用mysql5.x的版本,一些函数已经不知道支不支持,我的同事建议我使用like、rlike模糊匹配的方式,身为数据人我不太喜欢用这种手段,因为他们比较低效。于是我想这里总结一下

    2024年02月16日
    浏览(11)
  • 深入解析C语言中的字符串和字符串处理函数

    标题:详解C语言中的字符串和字符串处理函数 目录: 1.引言 2.什么是C语言中的字符串 3.字符串的表示方式 4.C语言中的字符串处理函数 5.例子:使用字符串处理函数的示例代码 6.总结 在C语言中,字符串是一种常见的数据类型,用于存储一串字符。本篇博客将详细介绍C语言中

    2024年02月15日
    浏览(11)
  • 字符串的全面解析

    目录 前言: 字符串的赋值   字符串的初始赋值两种:   输出的形式:   输入赋值四种方法:   在函数中的赋值(复制): 小问题: 字符串处理函数string: 多维字符串: 为什么非要在字符串后加\\\'\\0\\\'的问题。 子函数调用字符串: 字符串的错误使用方法: 通过单个元素的比较

    2024年02月07日
    浏览(12)
  • 字符函数和字符串函数解析及模拟实现

    字符串以’\\0’作为结束标志,strlen函数返回的是在字符串中’\\0’前面出现过的字符个数(不包括’\\0’)。 参数指向的字符串必须以’\\0’结束。 注意函数的返回值位size_t, 是无符号的 。 Copies the C string pointed by source into the array pointed by destination, including the terminating null c

    2024年02月16日
    浏览(14)
  • 解析GPS数据(长字符串解析示例)

    这里GPS一般返回的都是大量的数据,而且是一行行的那种,大部分数据也不太用的到,所以这个时候用串口DMA空闲中断其实就意义不大,这样我们就可以用一种新的思路来进行数据解析,专门针对这样的数据!!! 这里我用的大概长这样,还有很多其他版本的,不过区别不大

    2024年02月08日
    浏览(15)
  • Oracle解析JSON字符串

    假设某个字段存储的JSON字符串,我们不想查出来后通过一些常见的编程语言处理( JSON.parse() 或者是 JSONObject.parseObject() 等),想直接在数据库上处理,又该如何书写呢? 其实在 ORACLE 中也支持多种机制去处理JSON数据,例如有操作函数JSON_ARRAY、JSON_EXISTS、JSON_VALUES、JSON_TABLE、

    2024年02月16日
    浏览(17)
  • .NET实现解析字符串表达式

    我们创建了一个 School 对象,其中包含了教师列表和学生列表。现在,我们需要计算教师平均年龄和学生平均年龄。 如果我们将计算教师平均年龄的公式交给用户定义,那么用户可能会定义一个字符串来表示: Teachers.Sum(Age)/Teachers.Count 或者可以通过lambda来表示: teachers.Averag

    2023年04月21日
    浏览(8)
  • java解析多层嵌套json字符串

    在java 程序中,经常会涉及到各种变量值提取的问题,下面给出简单的示例及说明: JSON实际上也是键值对(\\\"key\\\":\\\"value\\\"),key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null) value如果是字符串,用jsonobj.getString(\\\"key\\\")获取 value如果是数

    2024年02月15日
    浏览(16)
  • 掌握字符与字符串:C语言中的神奇函数解析(二)

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 声明:int strncmp(const char *str1, const char *str2, size_t n) str1 -- 要进行比较的第一个字符串。 str2 -- 要进行比较的第二个字符串。 n -- 要比较的最大字符数。 作

    2024年03月09日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包