我有一个大数据库,它代表一个图表,其中包含大量不断增长的数据。 数据库看起来类似:
CREATE TABLE node (
id BIGSERIAL PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status TEXT NOT NULL DEFAULT 'new',
-- ... other columns ...
data JSONB
);
CREATE TABLE edge (
parent BIGINT REFERENCES node(id),
child BIGINT REFERENCES node(id)
);
-- ...
-- a few other tables with foreign keys to node
-- ...
现在我的数据库中有大量数据,某些查询开始陷入相当多的困境,因此我希望能够将我想要“存档”的节点移动到一个单独的表分区,而该分区不会得到阅读任何对时间敏感的查询。不过,我仍然可以轻松查询它们以进行历史分析。
理想情况下,我会在我的
archived BOOL NOT NULL DEFAULT false
表中添加一个 node
列,然后将其更改为 PARTITION BY LIST (archived)
。
不幸的是,Postgres 分区不允许我对
node.id
有唯一性约束,如果没有唯一性约束,我就无法在我的 REFERENCES
表中使用外键 edge
。
我可以删除
REFERENCES
外键关系,然后危险地生活,但我真的不喜欢那样。
我尝试添加
archived
列并在其上构建 BRIN
索引,但 Postgres 拒绝使用它。 我想我可以 CLUSTER node USING archived_idx
但要找到所需的 ACCESS EXCLUSIVE
锁的停机时间会很困难。
对于需要外键的表,是否有其他策略来对数据(或类似的策略)进行分区?
首先,4000万条记录本身并不算多。然而,当这些 JSON 对象很大或者大多数数据已经存档时,它可能会成为一种负担。
您可以通过在分区上而不是在父分区上生成主键来改进这一点:
CREATE TABLE node
(
id BIGINT GENERATED ALWAYS AS IDENTITY, -- use an identity
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status TEXT NOT NULL DEFAULT 'new',
archived BOOLEAN NOT NULL DEFAULT FALSE,
-- ... other columns ...
data JSONB
) PARTITION BY LIST (archived);
CREATE TABLE node_current PARTITION OF node
(
CONSTRAINT pkey_node_current
PRIMARY KEY (id)
)
FOR VALUES IN (FALSE);
CREATE TABLE node_archived PARTITION OF node
(
CONSTRAINT pkey_node_archived
PRIMARY KEY (id)
)
FOR VALUES IN (TRUE);
CREATE TABLE edge
(
parent BIGINT REFERENCES node_current (id),
child BIGINT REFERENCES node_current (id)
);
如果您进行更新,还有其他更好的解决方案可以跟踪记录的不同版本。但这取决于您的要求。