[MySQL Bug]bug#66301(Percona Bug#1035225)简析

———————————

先跑test case

1.创建测试表

CREATE TABLE t(

       id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

       k INT,

       c CHAR(1),

       UNIQUE KEY(k)) ENGINE=InnoDB;

2.当顺序执行如下SQL时
SQL1–INSERT INTO t(k) VALUES (1), (2), (3) ON DUPLICATE KEY UPDATE c=’1′;
SQL2–INSERT INTO t(k) VALUES (2), (4), (5) ON DUPLICATE KEY UPDATE c=’2′;
SELECT * FROM t;
id      k       c
1       1       NULL
2       2       2
3       3       NULL
4       4       NULL
5       5       NULL
在Binlog里记录的是先SQL1,再SQL2

使用DEBUG_SYNC来模拟并发的场景,并发执行上述两个SQL时,会得到不同的结果,具体见test case
SELECT * FROM t;
id      k       c
1       1       NULL
4       2       1
5       4       1
6       5       NULL
而在备库的执行结果则是按照串行执行,执行结果为:
1       1       NULL
2       2       2
3       3       NULL
4       4       NULL
5       5       NULL


如果binlog_format为statement模式时,这种情况就会造成主备数据不一致,因为在备库是按照串行化执行的。

根据test case,其模拟的场景是SQL1插入第一行等待,SQL2完成,SQL1再插入剩余的记录。
当insert出现dup key时如下代码逻辑对next_insert_id做了调整
sql/sql_insert.cc
write_record函数
1649         if (table->next_number_field)
1650           table->file->adjust_next_insert_id_after_explicit_value(
1651             table->next_number_field->val_int());

其中
table->next_number_field->val_int()是冲突记录的主键值,这样我们就可以理清这里的逻辑了
SQL1获得的自增区间为1,2,3
SQL2获得的自增区间为4,5,6
如下执行序列:
SQL1:1 1 NULL  next_insert_id =2
SQL2:4 2 NULL
SQL2: 5 4 NULL
SQL2:6 5 NULL
SQL1: 试图插入2 2 NULL,uniquekey冲突,改为update,记录为4 2 1,
next_insert_id=4+1=5
SQL1: 试图插入5 3,NULL,主键冲突,改为update,记录为5 4 1
因此最后的结果是
1       1       NULL
4       2       1
5       4       1
6       5       NULL
问题在于即使唯一索引(非主键)冲突,也可能会调整next_insert_id(当冲突记录主键值>当前next_insert_id时)。Percona已经在MySQL Buglist上report了这个bug,并且patch已经release
patch很简单,对上述情况区别对待。给table增加了一个成员变量next_number_field_updated

当在INSERT … ON DUPLICATE KEY UPDATE后,如果自增列在UPDATE中,设置该变量值为TRUE。
这样在函数write_record中,如果遇到DUP KEY,当next_number_field_updated为TRUE时,设置next_insert_id值(按照原先的逻辑 adjust_next_insert_id_after_explicit_value),否则next_insert_id保留为当前的 table->file->insert_id_for_cur_row,也就是该记录获得的自增值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值