#错误描述: 如果在创建表时定义了外键,则可以将具有外键的表创建到超表中
#为了重现,有下一张表:
CREATE TABLE ids (
measurement_id int DEFAULT 0,
description text DEFAULT 0,
m_id bigserial NOT NULL,
service_id int DEFAULT NULL,
time bigint NOT NULL DEFAULT cast((EXTRACT(EPOCH FROM now() AT TIME ZONE 'UTC') * 1000) as bigint),
user_id int DEFAULT NULL,
end_time DOUBLE PRECISION DEFAULT 0,
start_time int NOT NULL DEFAULT 0
);
CREATE INDEX ON ids (time DESC, user_id);
CREATE INDEX ON ids (time DESC, service_id);
SELECT create_hypertable('ids', 'start_time', chunk_time_interval => 604800016);
---------
CREATE TABLE IF NOT EXISTS metrics (
id bigserial NOT NULL,
duration real DEFAULT NULL,
metric integer DEFAULT 0,
m_id bigint NOT NULL,
time bigint NOT NULL DEFAULT 0
);
ALTER TABLE metrics ADD PRIMARY KEY (time, m_id);
CREATE INDEX ON metrics (time DESC);
CREATE INDEX ON metrics (time DESC, measurement );
CREATE INDEX ON metrics (time DESC, m_id );
grant all privileges on ids, metrics to your_db_user;
SELECT create_hypertable('metrics', 'time' , chunk_time_interval => 604800016);
SELECT table_catalog, table_schema, table_name, privilege_type FROM information_schema.table_privileges WHERE grantee = 'your_db_user';
---------
DROP TABLE IF EXISTS resource;
CREATE TABLE resource(
id int NOT NULL,
cpu text DEFAULT 0,
storing text DEFAULT 0,
memory text DEFAULT 0
);
ALTER TABLE resource ADD PRIMARY KEY (id);
CREATE SEQUENCE resource_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE resource_id_seq
OWNER TO your_db_user;
ALTER TABLE resource ALTER COLUMN id SET DEFAULT nextval('resource_id_seq'::regclass);
---------
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
DROP TABLE IF EXISTS ns;
CREATE TABLE ns(
id bigint NOT NULL,
uuid uuid NOT NULL DEFAULT uuid_generate_v4 (),
availability double precision,
faultTolerance boolean,
activated boolean,
UNIQUE (id, uuid),
PRIMARY KEY(id),
CONSTRAINT fk_resource
FOREIGN KEY(id)
REFERENCES resource(id)
ON DELETE CASCADE
);
CREATE SEQUENCE ns_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE ns_id_seq
OWNER TO your_db_user;
ALTER TABLE ns ALTER COLUMN id SET DEFAULT nextval('ns_id_seq'::regclass);
---------
DROP TABLE IF EXISTS authentication;
CREATE TABLE authentication(
id integer NOT NULL,
username character varying(255) NOT NULL,
password character varying(255) NOT NULL,
host character varying(255) NOT NULL,
port character varying(10) NOT NULL,
PRIMARY KEY(id)
);
CREATE SEQUENCE auth_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE auth_id_seq
OWNER TO your_db_user;
ALTER TABLE authentication ALTER COLUMN id SET DEFAULT nextval('auth_id_seq'::regclass);
---------
DROP TABLE IF EXISTS job;
CREATE TABLE job(
id int NOT NULL,
interval integer NOT NULL,
auth_id integer REFERENCES authentication (id),
ns_id integer REFERENCES ns (id),
UNIQUE (auth_id, ns_id),
PRIMARY KEY(id)
);
ALTER TABLE job
ADD CONSTRAINT fk_auth_id
FOREIGN KEY (id) REFERENCES authentication (id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE job
ADD CONSTRAINT fk_ns_id
FOREIGN KEY (id) REFERENCES ns (id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED;
CREATE SEQUENCE job_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE job_id_seq
OWNER TO your_db_user;
ALTER TABLE job ALTER COLUMN id SET DEFAULT nextval('job_id_seq'::regclass);
---------
DROP TABLE IF EXISTS job_metric;
CREATE TABLE job_metric (
id int NOT NULL,
j_id int NOT NULL REFERENCES job (id),
mj_id bigint NOT NULL,
jm_time bigint NOT NULL
);
CREATE INDEX ON job_metric (jm_time DESC);
CREATE INDEX ON job_metric (jm_time DESC, id);
CREATE INDEX ON job_metric (jm_time DESC, mj_id);
ALTER TABLE job_metric ADD PRIMARY KEY (jm_time, id);
grant all privileges on job_metric to your_db_user;
SELECT create_hypertable('job_metric', 'jm_time' , chunk_time_interval => 604800016);
CREATE SEQUENCE mjob_metric_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE mjob_metric_id_seq
OWNER TO your_db_user;
ALTER TABLE job_metric ALTER COLUMN id SET DEFAULT nextval('mjob_metric_id_seq'::regclass);
---------
创建表后,我在使用PostgreSQL 12.6 的数据库中使用了@Laurenz 提出的解决方案,使用 timescaledb 1.7.5 的扩展,如下所示:
#用适当的值填充表格:
UPDATE job_metric AS jm_point
SET jm_time = qm.time
FROM metrics AS qm
WHERE qm.m_id = jm_point.mj_id;
#然后将其设置为NOT NULL:
ALTER TABLE job_metric ALTER jm_time SET NOT NULL;
#定义你的外键:
ALTER TABLE job_metric
ADD FOREIGN KEY (mj_id, jm_time)
REFERENCES metrics (time, m_id) MATCH FULL;
#最后一个引用表启用外键的响应: 查询在40毫秒内成功返回。
预期行为: 这个想法是使用表 job_metric 在一个甚至多对多的关系中访问作业和指标表的信息。
实际行为和错误: 创建了表并创建了 FK,但在 job_metric 中插入数据时无法使用,如下所述:
INSERT INTO job_metric (j_id, mj_id, jm_time)
VALUES(13, 185063, 1621957192266);
错误:不支持超表的外键上下文:SQL 语句“ALTER TABLE _timescaledb_internal._hyper_5_5_chunk ADD CONSTRAINT”5_13_job_metric_j_id_mj_id_jm_time_fkey”外键(j_id,mj_id,jm_time)参考 qmetrics(“时间”,m_id)匹配完整“PL/pgSQL 函数.chunk_constraint_add_table_constraint(_timescaledb_catalog.chunk_constraint) 执行 SQL 状态的第 42 行:0A000
***根据https://docs.timescale.com/timescaledb/latest/overview/limitations/##distributed-hypertable-limitations,看起来上述错误是超表限制的一部分:
不支持引用超表的外键约束。
#Request: 鉴于上述信息和错误,是否有人知道在数据库级别使用 timescaledb 扩展和主要是超表建立关系(多对多或一对多)的任何解决方案?
实际上,当我尝试使用 Django Rest Framework 在表 metrics 和 job_metric 之间创建多对多关系时,我得到了类似的上述错误:
class Job_Metrics(models.Model):
job = models.OneToOneField(Job, on_delete=models.CASCADE)
metrics = models.ManyToManyField(Metrics)
time = models.IntegerField(default=0)
运行应用程序指标直接指出metrics_db: $ python3 manage.py migrate metrics --database=metrics_db
要执行的操作:应用所有迁移:指标运行迁移:应用 metrics.0002_job...Traceback(最近一次调用最后):文件“/var/myproject/myprojectenv/lib/python3.8/site-packages/django/db/ backends/utils.py",第 84 行,在 _execute return self.cursor.execute(sql, params) psycopg2.errors.FeatureNotSupported:不支持超表的外键
如果有人知道解决方案或有想法在 REST API 级别处理上述错误,请您分享您的想法,以访问数据关联表(指标和作业)并在需要删除时一起修改它们,例如,一个job_metric。到目前为止,使用超表修正 timescaledb 扩展似乎不是一个可行的解决方案。