暂无图片
暂无图片
暂无图片
暂无图片
3
暂无图片

MYSQL为什么分区要加入主键和唯一索引?

2730

MYSQL普通表 在线 改成 分区表

上篇我们遇到了困难,主要是分区字段必须加入到主键列表,还有唯一索引组合中,否则不让我们建索引! 很多朋友说是为了保证唯一性? 因为分区分成了多个物理表,无法保证全局唯一,只能局部唯一性! 

  这是对的吗? 我们来做实验证实下看看

CREATE TABLE books.`dba_unique_test` 
(
  `Id` bigint(20NOT NULL AUTO_INCREMENT,
  `Money` decimal(20,2NOT NULL,
  `status` smallint(3NOT NULL , 
  `flow_no` varchar(33NOT NULL COMMENT '流水号',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`Id`,create_time)
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='流水表'
PARTITION BY RANGE (TO_DAYS(create_time))
(
 PARTITION create_time_20200826 VALUES LESS THAN (738028)  ENGINE = InnoDB,
 PARTITION create_time_20200902 VALUES LESS THAN (738035ENGINE = InnoDB,
 PARTITION create_time_20200909 VALUES LESS THAN (738042ENGINE = InnoDB,
 PARTITION create_time_20200916 VALUES LESS THAN (738049ENGINE = InnoDB,
 PARTITION create_time_20200923 VALUES LESS THAN (738056ENGINE = InnoDB,
 PARTITION create_time_20200930 VALUES LESS THAN (738063ENGINE = InnoDB,
 PARTITION create_time_20201007 VALUES LESS THAN (738070ENGINE = InnoDB,
 PARTITION create_time_20201014 VALUES LESS THAN (738077ENGINE = InnoDB,
 PARTITION create_time_20201021 VALUES LESS THAN (738084ENGINE = InnoDB,
 PARTITION create_time_20201028 VALUES LESS THAN (738091ENGINE = InnoDB,
 PARTITION create_time_20201104 VALUES LESS THAN (738098ENGINE = InnoDB,
 PARTITION create_time_20201111 VALUES LESS THAN (738105ENGINE = InnoDB,
 PARTITION create_time_20201118 VALUES LESS THAN (738112ENGINE = InnoDB,
 PARTITION create_time_20201125 VALUES LESS THAN (738119ENGINE = InnoDB,
 PARTITION create_time_20201202 VALUES LESS THAN (738126ENGINE = InnoDB,
 PARTITION create_time_20201209 VALUES LESS THAN (738133ENGINE = InnoDB,
 PARTITION create_time_20210106 VALUES LESS THAN (738161ENGINE = InnoDB,
 PARTITION create_time_20210113 VALUES LESS THAN (738168ENGINE = InnoDB,
 PARTITION create_time_20210120 VALUES LESS THAN (738175ENGINE = InnoDB,
 PARTITION create_time_20210127 VALUES LESS THAN (738182ENGINE = InnoDB,
 PARTITION create_time_DEFAULTE VALUES LESS THAN MAXVALUE
 );

复制

然后造一点数据

--1 造数据
insert into dba_unique_test
(Id, amount, status, flow_no, create_time, update_time) VALUES
(130.001'001''2021/9/2 17:08:45''2021/9/2 17:08:45'), 
(240.002'002''2021/9/2 17:09:09''2021/9/2 17:09:09'), 
(350.001'003''2021/9/2 17:09:29''2021/9/2 17:09:29');

复制


--2 插入重复的ID 可以的
insert into dba_unique_test (Id, amount, status, flow_no) VALUES (130.001'003');

复制



--3 插入 ID+TIME 重复值  是不可以的。 说明主键冲突
insert into dba_unique_test
(Id, amount, status, flow_no, create_time, update_time) VALUES
(130.001'001''2021/9/2 17:08:45''2021/9/2 17:08:45');

复制



--4 创建联合唯一索引 ID+TIME 在ID有重复下 是可以的
CREATE UNIQUE INDEX `idx_id_time` USING BTREE ON books.dba_unique_test (id, create_time);

复制


我觉得 加入分区字段 不是为了判断唯一性,你看我上面实验 就无法判断唯一性,主键加入分区字段 好理解 就是为了定位分区

--6 创建FLOW+time唯一索引 看能否保证唯一性
--目前数据如下 可以看出 FLOW_NO + CREATE_TIME 是没有重复值的
Id amount status flow_no create_time         update_time
1 30.00 1     001     2021/9/2 17:08:45 2021/9/2 17:08:45
1 30.00 1     003     2021/9/2 17:11:10 2021/9/2 17:11:10
1 30.00 1     003     2021/9/2 17:20:03 2021/9/2 17:20:03
2 40.00 2     002     2021/9/2 17:09:09 2021/9/2 17:09:09
3 50.00 1     003     2021/9/2 17:09:29 2021/9/2 17:09:29


CREATE UNIQUE INDEX `idx_flow_time` USING BTREE ON dba_test_big_table_source.dba_unique_test (flow_no, create_time);
--居然成功了 那么它遵循了标准定义 也就是FLOW_NO+TIME的双值相同才会冲突。

复制


--7 单独建唯一索引
CREATE UNIQUE INDEX `idx_uq_flow` USING BTREE ON books.dba_unique_test (flow_no);
"Lookup Error - MySQL Database Error: A UNIQUE INDEX must include all columns in the table's partitioning function"
--8 普通索引
CREATE  INDEX `idx_btree_flow` USING BTREE ON books.dba_unique_test (flow_no);
是OK

复制


这就奇怪 唯一索引强制加入分区字段 为了什么?无法保证唯一性  如果是为了提高效率,为什么其他非唯一是不用添加的,逼定二级索引的VALUE是指向主键的,而且主键包含了分区字段。


结论就是 无法保证唯一, 无论是全局还是本地都无法保证原来的唯一性.


至于为什么强制 加入唯一索引和主键呢? 请大家留言

文章转载自海鲨数据库架构师,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

手机用户6058
暂无图片
2年前
评论
暂无图片 0
唯一性是指唯一索引字段数据的唯一性,你上面第一个id是普通自增索引,并不是唯一索引,自然允许重复。然后联和主键(ID+time)是必须唯一的,这里是id+time的值组合起来唯一吧,并不是说单个唯一也算的,所有ID单个唯一是允许的。假设分区键和主键是两个不同的列,在进行插入操作时,虽然也指定了分区键,但还是需要扫描所有分区才能判断插入的主键值是否违反了唯一性约束。可能考虑性能问题吧,牺牲了一定的灵活性,这样单独的唯一索引不允许存在了
2年前
暂无图片 点赞
评论
吊车尾的小七
暂无图片
3年前
评论
暂无图片 0
个人理解: 对range分区有一个好处,分区的列值连续时,插入一条新数据,判断是否满足唯一性约束,只需在一个分区里检查唯一性。
3年前
暂无图片 点赞
1
回复
暂无图片 0
只能在分区表里完成唯一性,无法在全表中完成唯一性.
2年前
暂无图片 点赞
回复