【唯一索引写入冲突会导致ONLINE DDL报错】

唯一索引写入冲突会导致ONLINE DDL报错

现象

最近对业务大表做了归档,有很大的空间未释放,于是想着alter table xxxx engine=innodb进行表空间的收缩,由于此操作是支持online ddl,于是抽了一个业务低峰期搞,发现DDL失败,并报唯一索引冲突。


一、为什么收缩一下表空间会报唯一约束冲突?

于是我在网上查,我查到了一篇文章,链接:http://www.136.la/nginx/show-169305.html
我就备份了表的数据去测试环境复现,cc_coupon_ct_24表结构如下:

mysql> show create table cc_coupon_ct_24\G
*************************** 1. row ***************************
       Table: cc_coupon_ct_24
Create Table: CREATE TABLE `cc_coupon_ct_24` (
  `coupon_ct_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `biz_type` bigint(11) NOT NULL DEFAULT '0' COMMENT '(0:)',
  `merchant_id` bigint(20) unsigned NOT NULL,
  `code` varchar(50) NOT NULL,
  `wid` bigint(20) unsigned NOT NULL,
  `card_template_id` bigint(20) unsigned NOT NULL,
  `use_adapt_object_id` bigint(20) DEFAULT NULL COMMENT '&',
  `start_date` datetime DEFAULT NULL,
  `exp_date` datetime DEFAULT NULL,
  `use_time` datetime DEFAULT NULL,
  `use_channel` int(11) DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `app_channel` tinyint(4) DEFAULT '1',
  `business_id` varchar(50) DEFAULT NULL,
  `acquire_scene` int(9) DEFAULT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `acquire_time` datetime DEFAULT NULL,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `card_template_type` int(11) DEFAULT NULL,
  `source` tinyint(4) DEFAULT NULL,
  `operator` varchar(32) DEFAULT NULL,
  `add_to_wechat` tinyint(4) DEFAULT '0',
  `name` varchar(20) DEFAULT NULL,
  `acquire_store_id` bigint(20) DEFAULT NULL,
  `send_channel` int(11) DEFAULT NULL,
  `wsc1_ct` int(11) DEFAULT NULL,
  `allow_buy` int(11) NOT NULL DEFAULT '0' COMMENT '0- 1-',
  `acquire_order_id` varchar(64) DEFAULT NULL COMMENT 'id',
  PRIMARY KEY (`coupon_ct_id`),
  UNIQUE KEY `uidx_code` (`merchant_id`,`code`) USING BTREE,
  KEY `idx_union1` (`card_template_id`,`merchant_id`,`wid`) USING BTREE,
  KEY `idx_acquireTime` (`acquire_time`) USING BTREE,
  KEY `idx_useTime` (`use_time`) USING BTREE,
  KEY `idx_cti_mi_cci` (`card_template_id`,`merchant_id`,`coupon_ct_id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=22746161 DEFAULT CHARSET=utf8mb4 COMMENT='-ct'

session 1:针对些表发起ONLINE DDL

alter table cc_coupon_ct_24 engine=innodb;

session 2:执行插入冲突的数据

mysql> insert into cc_coupon_ct_24 values (null,0,42,921110281014034154,272236326,32514,NULL,now(),now(),NULL,NULL,1,1,'',222,now(),now(),now(),0,3,'',0,'wewwe',211,null,1,0,'');
ERROR 1062 (23000): Duplicate entry '42-921110281014034154' for key 'uidx_code'

在DDL快要执行完成的时候,session 1:

mysql> alter table cc_coupon_ct_24 engine=innodb;
ERROR 1062 (23000): Duplicate entry '42-921110281014034154' for key 'uidx_code'

2.那主键冲突会不会影响ONLINE DDL?

session 1:发起ONLINE DDL

alter table cc_coupon_ct_24 engine=innodb;

session 2:插入主键冲突的数据

mysql> insert into cc_coupon_ct_24 values (13274941,0,43,921110281014034154,272236326,32514,NULL,now(),now(),NULL,NULL,1,1,'',222,now(),now(),now(),0,3,'',0,'wewwe',211,null,1,0,'');
ERROR 1062 (23000): Duplicate entry '13274941' for key 'PRIMARY'

session 1:最终DDL成功

mysql> alter table cc_coupon_ct_24 engine=innodb;
Query OK, 0 rows affected (4 min 32.98 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时 唯一索引重复值报错问题的出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值