我有从 docker-compose 运行的 Citus,我从官方网站获取了 yaml 并最初从 2 个节点运行它
docker-compose -p citus up --scale worker=2 -d
然后我添加表格
CREATE TABLE IF NOT EXISTS messages (
text TEXT NOT NULL,
"from" CHARACTER VARYING NOT NULL,
"to" CHARACTER VARYING NOT NULL,
"shardId" CHARACTER VARYING NOT NULL
);
然后我打电话要一个
SELECT create_distributed_table('messages', 'shardId');
shardId 是来自“from”和“to”变量的哈希值,范围从 0 到 31,到目前为止一切正常,我看到每个聊天都有自己的分片。
但是当我尝试重新分片我的集群时
set POSTGRES_PASSWORD=pass && docker-compose -p citus up --scale worker=5 -d
并通过节点重新平衡数据
SELECT citus_rebalance_start();
我收到错误,我无法在没有 pk 的情况下重新平衡表,因此我添加了一个 pk(id),然后我收到错误,我无法将 create_distributed_table 的值放入 pk 或在唯一约束下
SELECT create_distributed_table('messages', 'shardId');
错误:无法对“消息”创建约束 详细信息:分布式关系不能具有不包含分区列的 UNIQUE、EXCLUDE 或 PRIMARY KEY 约束(如果 EXCLUDE,则使用等式运算符)。
所以我陷入了死胡同,我该怎么做才能操作 create_distributed_table 方法中的密钥?
假设你做了这样的事情:
db<>fiddle 的演示
alter table messages
add column id int generated always as identity
,add constraint pk primary key(id);
您的情况类似于分区尝试 - 它具有相同的要求
create table messages_partitioned(like messages including all)
partition by list("shardId");
甚至类似地表达了该要求:
ERROR: unique constraint on partitioned table must include all partitioning columns
DETAIL: PRIMARY KEY constraint on table "messages_partitioned" lacks column "shardId" which is part of the partition key.
由于看起来您只是添加了 id 来满足 citus 分片要求,因此您可以将其替换为复合主键 - 给它两个字段并确保
shardId
是其中之一:
alter table messages
drop constraint pk
,add constraint pk primary key(id,"shardId");
现在分片和分区都可以正常工作了:
create table messages_partitioned(like messages including all)
partition by list("shardId");
更多内容来自第 5 章数据定义:5.12。表分区,5.12.2.3。限制:
要在分区表上创建唯一或主键约束,分区键不得包含任何表达式或函数调用,并且约束的列必须包含所有分区键列。存在这种限制是因为构成约束的各个索引只能直接在自己的分区内强制执行唯一性;因此,分区结构本身必须保证不同分区之间不存在重复。
类似地,排除约束必须包含所有分区键列。此外,约束必须比较这些列是否相等(不是例如 &&)。同样,此限制源于无法强制执行跨分区限制。该约束可能包括不属于分区键的其他列,并且它可能会将这些列与您喜欢的任何运算符进行比较。