分区表主键插入重复 bug

我测试了一下range partition。没有出现add partition后primary key失效的情况。貌似这个问题仅出现在range colums partition情况下。
我的测试如下:
CREATE TABLE p3 (
id bigint(12) NOT NULL,
create_time int NOT NULL,
brand_type varchar(8) NOT NULL DEFAULT ‘Y’ ,
PRIMARY KEY (id,create_time,brand_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
PARTITION BY RANGE (create_time)
(PARTITION p20240520 VALUES LESS THAN (20240520),
PARTITION p20240521 VALUES LESS THAN (20240521)) ;
– 插入数据
INSERT INTO test.p3(id, create_time, brand_type) VALUES (1, 20240519, ‘A’);
INSERT INTO test.p3(id, create_time, brand_type) VALUES (2, 20240519, ‘B’);
INSERT INTO test.p3(id, create_time, brand_type) VALUES (3, 20240519, ‘C’);
INSERT INTO test.p3(id, create_time, brand_type) VALUES (4, 20240519, ‘Z’);
– 添加分区
alter TABLE p3 add partition (
PARTITION p20240522 VALUES LESS THAN (20240522),
PARTITION p20240523 VALUES LESS THAN (20240523)
);
– 再插入数据
INSERT INTO test.p3(id, create_time, brand_type) VALUES (2, 20240519, ‘B’);
INSERT INTO test.p3(id, create_time, brand_type) VALUES (3, 20240519, ‘C’);
INSERT INTO test.p3(id, create_time, brand_type) VALUES (4, 20240519, ‘Z’);
报错:mysql> INSERT INTO test.p3(id, create_time, brand_type) VALUES (2, 20240519, ‘B’);
ERROR 1062 (23000): Duplicate entry ‘2-20240519-B’ for key ‘p3.PRIMARY’
mysql> INSERT INTO test.p3(id, create_time, brand_type) VALUES (3, 20240519, ‘C’);
ERROR 1062 (23000): Duplicate entry ‘3-20240519-C’ for key ‘p3.PRIMARY’
mysql> INSERT INTO test.p3(id, create_time, brand_type) VALUES (4, 20240519, ‘Z’);
ERROR 1062 (23000): Duplicate entry ‘4-20240519-Z’ for key ‘p3.PRIMARY’

这个和 add partition 本身没关系,是因为 range partition 的分区不是严格递增的,导致插入数据的时候定位到了错误的分区上,不在同一个分区上的话,主键的唯一性检查就会失效。

执行新增分区的行为不兼容 mysql,mysql 会直接报错:ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition

就像这个提到的,TiDB 正确的行为应该和 mysql 一样报错。

约束不应该是表级的吗,分区自己检查自己的?

这个和内部实现的原理有关系,有兴趣的话可以了解下 TiDB 的 key value 的编码规则和分区表的实现

版主有没有尝试过建立一些联合主键试试

个人觉得这里失效的是唯一性约束。key-value对应的应该是索引,即存储。两者应该还是有区别。若是说pk在table rows存储时参与做为key的一部分,是对于clustered table。对于nonclustered table是用的tidb rowid