mysql在onlineDDL操作时 唯一索引的问题

Posted 翔之天空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql在onlineDDL操作时 唯一索引的问题相关的知识,希望对你有一定的参考价值。

一、现象:
onlineDDL时候, 在有唯一索引时, 在 inplace rebluid时候 需要对DML的操作临时存放到row log中,在DDL变更好了 应用DML操作时 如果有的DML是唯一键冲突 会报错出来  并回滚整个onlineDDL操作。
二、测试:
--onlineDDL在 唯一索引冲突时 报错
 
--表结构
[root@localhost][wangx_test]> show create table test_onlineddl_uk\\G
*************************** 1. row ***************************
       Table: test_onlineddl_uk
Create Table: CREATE TABLE `test_onlineddl_uk` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL DEFAULT '0',
  `c` char(120) NOT NULL DEFAULT '',
  `pad` char(60) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_pad` (`pad`),
  KEY `k_1` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=8000001 DEFAULT CHARSET=utf8mb4 MAX_ROWS=1000000
1 row in set (0.00 sec)


--session1
[root@localhost][wangx_test]> select * from test_onlineddl_uk order by id desc limit 3;
+----------+---------+-------------------------+-------------+
| id       | k       | c                       | pad         |
+----------+---------+-------------------------+-------------+
| 10000001 |       1 | 11                      | 11          |
|  8000000 | 4020159 | 28697186640-99593610830 | 98145415295 |
|  7999999 | 3991628 | 96825346858-95740938530 | 31022410438 |
+----------+---------+-------------------------+-------------+
3 rows in set (0.00 sec)

--进行onlineDDL其中的rebuild操作,操作的过程中 执行如下 session2、3、4、5的操作
[root@localhost][wangx_test]> alter table test_onlineddl_uk add column hahaha int not null default 0 ;




--session2  新增一条数据
[root@localhost][wangx_test]> insert into test_onlineddl_uk values(10000002,1,'11','22');
Query OK, 1 row affected (0.01 sec)

--session3  新增一条数据失败 和session2的  字段pad的唯一索引冲突
[root@localhost][wangx_test]> insert into test_onlineddl_uk values(10000003,1,'11','22');
ERROR 1062 (23000): Duplicate entry '22' for key 'uk_pad'

--session4  新增一条数据
[root@localhost][wangx_test]> insert into test_onlineddl_uk values(10000003,1,'11','33');
Query OK, 1 row affected (0.00 sec)


--session5   查询数据  session2 和 session4 的数据都可以查询到。 在DDL期间产生的数据,会按照正常操作一样,写入原表,记redolog、undolog、binlog,并同步到从库去执行,只是额外会记录在row log中
[root@localhost][wangx_test]> select * from test_onlineddl_uk order by id desc limit 3;
+----------+---+----+-----+
| id       | k | c  | pad |
+----------+---+----+-----+
| 10000003 | 1 | 11 | 33  |
| 10000002 | 1 | 11 | 22  |
| 10000001 | 1 | 11 | 11  |
+----------+---+----+-----+
3 rows in set (0.00 sec)



--session1  报错 因为row log的DML中 记录了 session2、3、4 的DML语句, 顺序执行 因session2的唯一索引报错 从而导致onlineDDL的失败。
[root@localhost][wangx_test]> alter table test_onlineddl_uk add column hahaha int not null default 0 ;
ERROR 1062 (23000): Duplicate entry '22' for key 'uk_pad'
--onlineDDL在 主键冲突时 没有问题
--session3   如果是主键冲突,那么不影响onlineDDL中应用row log的操作  
[root@localhost][wangx_test]> insert into test_onlineddl_uk values(10000002,1,'11','33');
ERROR 1062 (23000): Duplicate entry '10000002' for key 'PRIMARY'

--session1  onlineDDL中主键冲突不会记录到row log中  所以应用row log不会报错
[root@localhost][wangx_test]> alter table test_onlineddl_uk add column hahaha int not null default 0 ;
Query OK, 0 rows affected (2 min 20.82 sec)
Records: 0  Duplicates: 0  Warnings: 0
三、原因:源码分析
row_log_table_apply_insert_low                //(insert行为)row log增量DML日志过程
|-row_ins_clust_index_entry_low                 //对于 聚簇索引 的数据插入
  |-row_ins_duplicate_error_in_clust_online       //先检测主键是否冲突 冲突的话 err != DB_SUCCESS
  |-row_log_table_insert                          //err == DB_SUCCESS & onlineDDL的情况下  再插入row log增量DML日志  所以在onlineDDL时 主键冲突不会影响
|-row_ins_sec_index_entry_low                   //对于 二级索引 的数据插入
  |-row_log_online_op_try                         //先插入row log增量DML日志
  |-row_ins_scan_sec_index_for_duplicate          //再进行唯一性约束检查  会导致以上onlineDDL时  唯一索引重复值报错问题的出现

以上是关于mysql在onlineDDL操作时 唯一索引的问题的主要内容,如果未能解决你的问题,请参考以下文章

mysql在onlineDDL操作时 唯一索引的问题

mysql在onlineDDL操作时 唯一索引的问题

mysql在onlineDDL操作时 唯一索引的问题

MySQL Percona Toolkit--pt-osc与online DDL选择

关于MySQL Online DDL

MySql批量插入与唯一索引问题