对rename后的表插入数据,报错:ERROR 1062 (23000): Duplicate entry '1' for key 'my_table.PRIMARY'

为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:

【概述】 场景 + 问题概述
需要通过rename表来更新表数据

【应用框架及开发适配业务逻辑】
线上库prod,待上线库beta
通过mysql客户端访问tidb,将beta库中表rename到prod中,实现表数据更新。
再对prod库中表做insert into,报错
ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘my_table.PRIMARY’

【背景】 做过哪些操作
连接tidb server1,创建2个库beta和prod,beta库中一张表my_table,写入一条数据
create database beta;
CREATE TABLE beta.my_table (name VARCHAR(50), email VARCHAR(100), age INT, city VARCHAR(50), country VARCHAR(50));
INSERT INTO beta.my_table (name, email, age, city, country) VALUES (‘NSerldQ’, ‘bHiNV@example.com’, 19, ‘WHwSzoz’, ‘KyPBL’);

create database prod;

连接tidb server2,rename表,使得beta.my_table变成prod.my_table,并drop beta库。之后往表prod.my_table插入一条数据
rename table beta.my_table to prod.my_table;
drop database beta;
INSERT INTO prod.my_table (name, email, age, city, country) VALUES (‘NSerldQ’, ‘bHiNV@example.com’, 19, ‘WHwSzoz’, ‘KyPBL’);

【现象】 业务和数据库现象
报错:ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘my_table.PRIMARY’

【问题】 当前遇到的问题
报错:ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘my_table.PRIMARY’

【业务影响】

【TiDB 版本】
v8.1.0

【附件】 相关日志及监控

经测试,v7.5.1版本没有此问题,相同操作不会报Duplicate entry ERROR

已测试方案:
1、建表时设置AUTO_ID_CACHE为1,试图使用MySQL兼容模式
测试结果:通过部分tidb server插入数据能够获取全局自增id,但仍有部分tidb server插入数据仍然使用预分配id,导致Duplicate entry
2、建表时设置SHARD_ROW_ID_BITS
测试结果:不起作用,出现Duplicate entry ERROR
3、设置一个自增字段_id作为主键
测试结果:不起作用,出现Duplicate entry ERROR
4、设置一个字段_id作为主键并使用AUTO_RANDOM
测试结果:不报错,但该字段导致无法批量导入数据:tispark datasource api / import into

临时解决方案:
在将表由beta.my_table rename为prod.my_table后,删除beta库。

数据重复了吧

这里没有唯一约束,和数据无关,冲突的是_tidb_rowid

嗯,这是个什么场景呢? 表的结构不设定主键 或者 索引

是hadoop上的业务数据转存的tidb,这些数据在业务上没有主键

嗯,可以设定一个 auto 的主键,是不是这样也可以,

然后在试试,是否还会出现之前的问题

谢谢回复。

目前查到v6.4.0以后可通过建表时设置AUTO_ID_CACHE为1,来使用MySQL兼容模式,由TiDB服务进程分配自增ID,满足全局唯一和单调递增。

测试了一下,这样建表后rename后再插入,不再报Duplicate entry错误。后续继续观察一下稳定性和性能。

经测试,AUTO_ID_CACHE=1在上述场景下并不稳定。
在rename表到prod库,并drop beta库后,通过部分tidb server插入数据能够获取全局自增id,但仍有部分tidb server插入数据仍然使用预分配id,导致Duplicate entry。

replace INTO beta.my_table (name, email, age, city, country) VALUES (‘NSerldQ’, ‘bHiNV@example.com’, 19, ‘WHwSzoz’, ‘KyPBL’);

on duplicate key update

replace INTO

方式

这里的my_table没有主键。虽然是不得已,但我们业务上需要支持插入完全相同数据。

从正常的索引存储结构应该是table_id__tidb_rowid 。rename 不改变table_id

这应该是一个发号问题,对于没有主键的表,tidb给表一个隐式的自增_tidb_rowid。
对于这个自增_tidb_rowid,默认的发号策略是每个tidb server实例分得一个范围,比如0~30000,30001~60000,来保证唯一性。

上面场景引发的问题是,在rename表从beta库到prod库,并drop掉beta库后,该表在各tidb server实例中的自增范围被清除了,不论之前是什么,现在变成了初始的0~30000,30001~60000,导致插入新数据的_tidb_rowid与已有_tidb_rowid冲突。

对于数据量超过9w(_tidb_rowid值从1到90k+)的表,换不同tidb server插入数据,可以看到报错分别是
Duplicate entry ‘1’ for key ‘my_table.PRIMARY’
Duplicate entry ‘30001’ for key ‘my_table.PRIMARY’
Duplicate entry ‘60001’ for key ‘my_table.PRIMARY’

_tidb_rowid是一个问题,但是正常索引标记是带上table_id 的。有主键冲突,说明实际写入的最底层的table_id还是beta的

和索引没关系

you right。 是我想错了,光盯着报错内容了。

学习一下多个

建表时设置SHARD_ROW_ID_BITS也不起作用,仍然出现Duplicate entry ERROR

https://docs.pingcap.com/zh/tidb/stable/dev-guide-insert-data#主键为-auto_random-表插入数据

用这个试试

建表参数不对

检查重复数据