如何使用带有外键的时标超表并保持一对多关系?

问题描述

我正在尝试创建一个考虑最小冗余的数据库。我们想使用timescaledb超表(我运行postgresql v。12和timescaledb v。1.7.4)。创建表的postgresql代码如下-您可以在https://dbdiagram.io/d/5f992f0e3a78976d7b797ca2上查看dbdiagram或在Image of database此处查看表

CREATE TABLE "datapoints" (
  "id" bigserial UNIQUE NOT NULL,"tstz" timestamptz NOT NULL,"entity_id" bigint NOT NULL,"value" real NOT NULL,PRIMARY KEY ("tstz","entity_id")
);

CREATE TABLE "datapoint_quality" (
  "tstz" timestamptz NOT NULL,"datapoint_id" bigint NOT NULL,"flag_id" bigint NOT NULL,"datapoint_id","flag_id")
);

CREATE TABLE "quality_flags" (
  "id" bigserial PRIMARY KEY,"value" text
);

CREATE TABLE "sensor_types" (
  "id" bigserial PRIMARY KEY,"name" text UNIQUE NOT NULL
);

CREATE TABLE "sensors" (
  "tstz" timestamptz NOT NULL DEFAULT (Now()),"id" bigserial UNIQUE NOT NULL,"name" text NOT NULL,"parent" bigint NOT NULL,"type" bigint NOT NULL,"id")
);

CREATE TABLE "datapoint_annotation" (
  "tstz" timestamptz NOT NULL,"annotation_id" bigint NOT NULL,"annotation_id")
);

CREATE TABLE "annotations" (
  "id" bigserial PRIMARY KEY NOT NULL,"value" text NOT NULL
);

ALTER TABLE "datapoints" ADD FOREIGN KEY ("entity_id") REFERENCES "sensors" ("id");

ALTER TABLE "datapoint_quality" ADD FOREIGN KEY ("datapoint_id") REFERENCES "datapoints" ("id");

ALTER TABLE "datapoint_quality" ADD FOREIGN KEY ("flag_id") REFERENCES "quality_flags" ("id");

ALTER TABLE "sensors" ADD FOREIGN KEY ("parent") REFERENCES "sensors" ("id");

ALTER TABLE "sensors" ADD FOREIGN KEY ("type") REFERENCES "sensor_types" ("id");

ALTER TABLE "datapoint_annotation" ADD FOREIGN KEY ("datapoint_id") REFERENCES "datapoints" ("id");

ALTER TABLE "datapoint_annotation" ADD FOREIGN KEY ("annotation_id") REFERENCES "annotations" ("id");

CREATE UNIQUE INDEX ON "quality_flags" ("value");

CREATE UNIQUE INDEX ON "annotations" ("value");

到目前为止,一切都很好-接下来,我要创建超级表,其操作如下:

SELECT create_hypertable('datapoint_annotation','tstz');
SELECT create_hypertable('datapoint_quality','tstz');
SELECT create_hypertable('datapoints','tstz');
SELECT create_hypertable('sensors','tstz');

这对于前两行效果很好,但对于后两行却出现以下错误

ERROR:  cannot create a unique index without the column "tstz" (used in partitioning)
sql state: TS103

我可以在主键中将tstz包括为(“ id”,“ tstz”)并将其用作外键,但这给了我一对一的关系,为了实现最小的冗余,我希望拥有一对多关系。

我确定应该有某种方法可以做到-我想念的是什么?

解决方法

以外键约束从datapoint_qualitydatapoints为例。

要使其与分区表一起使用,您需要在datapoint上具有唯一约束。如错误消息所告知,此类约束必须包含分区键。这样你就结束了

ALTER TABLE datapoints ADD UNIQUE (id,tstz);

要引用datapoint_quality中的唯一约束,您还需要在该时间戳上加上时间戳:

ALTER TABLE datapoint_quality ADD datapoints_tstz timestamp with time zone;

您必须用适当的值填充它:

UPDATE datapoint_quality AS dq
SET datapoints_tstz = d.tstz
FROM datapoints AS d
WHERE d.id = dq.datapoint_id;

然后将其设置为非空:

ALTER TABLE datapoint_quality ALTER datapoints_tstz SET NOT NULL;

现在您可以定义外键:

ALTER TABLE datapoint_quality
   ADD FOREIGN KEY (datapoint_id,datapoints_tstz)
   REFERENCES datapoints (id,tstz) MATCH FULL;

没有其他方法可以对分区表具有外键约束。

,

在我拥有的数据库中测试了 Laurenz 提出的解决方案之后,并且在复制了本案例的原始数据库之后。我使用 PostgreSQL 12.6 和 timescaledb 1.7.5。

基本上,在为表 datapoint_quality 定义外键之前,我一直很好:

ALTER TABLE datapoint_quality
   ADD FOREIGN KEY (datapoint_id,tstz) MATCH FULL;

经过多次尝试(包括上面的尝试)来定义超表的外键后,我测试的两个数据库中都存在下一个错误:

错误:不支持超表的外键 Blockquote SQL 状态:0A000

根据https://docs.timescale.com/timescaledb/latest/overview/limitations/##distributed-hypertable-limitations,看起来上面的错误是hypertable限制的一部分:

不支持引用超表的外键约束。

考虑到这一点,有没有人知道在 DB 级别建立关系(1..* 或 ...)的任何解决方案? >

即使是在 timescaledb 或 PostgreSQL 中给出的 REST API 级别(例如 Django 或 Flask),我也没有找到更多解决方案。