首页 > mysql > mysql新增字段(alter table add column),报错:Duplicate entry
2017
06-07

mysql新增字段(alter table add column),报错:Duplicate entry

问题

执行一个增加字段的DDL语句脚本时,报错,错误如下:

Error 1062: Duplicate entry '111-2222' for key 'uniq_user_id'


重复执行报相同的错误。根据错误提示的条件去数据库中查询却只能查到一条记录,并没有重复记录。 DDL脚本无法执行,影响后续上线步骤。


分析


DDL语句脚本中只有1条DDL语句,添加1个字段的语句。
表数据量是156w,脚本正常运行几十秒内即可完成。


Google键入关键字:mysql alter table add column duplicate entry,搜索结果中有一个链接:

MySQL Bugs:#76895:Adding new column OR Drop column causes duplicate PK error,详细如下:

When running an online DDL operation, the thread that runs the ALTER TABLE statement applies an online log of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the online log. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction.

解释一下就是当执行Online DDL操作时,MySQL实际上是将DML缓存(该缓存大小由变量 innodb_online_alter_log_max_size控制,默认128M)起来,等DDL执行完成后再将缓存中的DML重新应用到表上。 如果有别的线程执行了DML操作,在DDL完成后,应用DML时,可能会出现duplicate entry错误。


实战

线上报错的表(user)只有一种操作会写入或更新数据:insert into … on duplicate key… ,且报Duplicate entry的字段上有唯一索引。如果没有冲突的记录则插入,否则就更新。找一张测试表来验证,执行ALTER TABLE ADD COLUMN操作,并同时执行insert into…on duplicate key…操作,观察DDL语句是否会有报错。

1 准备一张表,通过脚本循环插入1000w数据

2 先执行添加字段sql,再执行insert into … on duplicate key 操作,观察执行结果,复现了线上的问题现象,那说明当时线上就是因为DML更新了相同的唯一属性字段键值导致DDL执行失败,报错。


总结

Online DDL的原理简单一点理解就是将DML操作缓存起来,等到DDL执行完成后重新应用缓存中的DML语句,如果在Oline DDL执行过程中,DML操作产生了Duplicate entry错误,并不会直接影响DDL操作,而是在DDL执行完成最终应用DML时报错,导致DDL执行失败。

在MySQL Bug网站上,官方人员回复该现象并不是Bug,而是一种限制。在测试insert into … on duplicate key…以及update和insert语句时,如果直接执行DML操作,客户端会直接返回报错,但是从现象上看MySQL仍然将报错的DML语句放到了Oline DDL的缓存中。如果直接将报错语句从缓存中去除则不会影响DDL的正常执行,个人感觉要合理一些。


解决方案

执行DDL时,期间产生的DML会生成重复数据,无法通过MySQL的唯一约束校验,MySQL里会报错,最终导致DDL失败。因此可以在执行DDL期间不执行该类DML,这样就可以正常执行DDL了,具体步骤如下:

1 修改业务代码,确保没有生成重复数据的DML(DML改动的业务数据是统计能耗的变化量,短期内没有记录不影响最终的数据统计),发布服务
2 执行添加字段sql

3 回滚业务代码的改动,正常执行业务需要的DML,发布服务

其他

ps:推荐一个查询MySQL问题的官方网站:MySQL Bugs: https://bugs.mysql.com/ ,可以查询关于MySQL中几乎所有的问题。

本文》有 0 条评论

留下一个回复