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操作时 唯一索引的问题的主要内容,如果未能解决你的问题,请参考以下文章