我有一个表,其中包含PK ID,两个FK(两个其他ID)和一个时间戳。 我希望对该表进行限制,以便每个FK组合只能有有限的行数。 例如,如果有十多个具有相同FK的行,则应删除该时间戳中最旧的行。
当前,解决方案的想法是在插入之前触发一个触发器,该触发器应检查表中是否存在多于要插入的FK相同的行数。如果存在最旧的字段,则应删除时间戳。
有人可以帮助我实现这一点吗?
答案 0 :(得分:1)
该问题的另一种解决方案是使用数组列而不是行和INSERT INTO ... ON CONFLICT UPDATE ...
支持。
在线示例:https://www.db-fiddle.com/f/2y46V6EEVJLQ5cPNTDAUPy/0
结构:
CREATE TABLE test_rr (
id serial primary key,
fk_1 integer not null,
fk_2 integer not null,
latest timestamptz[] not null
);
CREATE UNIQUE INDEX idx_unique_rr ON test_rr (fk_1, fk_2);
正在上传数据:
INSERT INTO test_rr (fk_1, fk_2, latest)
VALUES (1, 2, array[current_timestamp])
ON CONFLICT (fk_1, fk_2) DO UPDATE SET latest = (array_cat(EXCLUDED.latest, test_rr.latest))[:10];
选择条目:
SELECT id, fk_1, fk_2, unnest(latest) AS ts FROM test_rr WHERE fK_1 = 1 AND fk_2 = 2;
...导致:
id | fk_1 | fk_2 | ts
-----+------+------+-------------------------------
652 | 1 | 2 | 2019-03-10 13:28:57.806489+01
652 | 1 | 2 | 2019-03-10 13:28:56.670678+01
652 | 1 | 2 | 2019-03-10 13:28:55.470668+01
652 | 1 | 2 | 2019-03-10 13:28:54.174111+01
652 | 1 | 2 | 2019-03-10 13:28:52.878719+01
652 | 1 | 2 | 2019-03-10 13:28:51.3748+01
652 | 1 | 2 | 2019-03-10 13:28:49.886457+01
652 | 1 | 2 | 2019-03-10 13:28:48.190317+01
652 | 1 | 2 | 2019-03-10 13:28:46.350833+01
652 | 1 | 2 | 2019-03-10 13:11:50.506323+01
(10 rows)
代替timestamptz[]
,您还可以创建自己的类型来支持更多列:
CREATE TYPE my_entry_data AS (ts timestamptz, data varchar);
CREATE TABLE test_rr (
id serial primary key,
fk_1 integer not null,
fk_2 integer not null,
latest my_entry_data[] not null
);
CREATE UNIQUE INDEX idx_unique_rr ON test_rr (fk_1, fk_2);
-- ...
INSERT INTO test_rr (fk_1, fk_2, latest)
VALUES (1, 2, array[(current_timestamp,'L')::my_entry_data])
ON CONFLICT (fk_1, fk_2) DO UPDATE
SET latest = (array_cat(EXCLUDED.latest, test_rr.latest))[:10];
SELECT id, fk_1, fk_2, tmp.ts, tmp.data
FROM test_rr, unnest(latest) AS tmp -- LATERAL function call
WHERE fK_1 = 1 AND fk_2 = 2;
但是,负载测试必须显示这实际上是否比触发器或其他方法快。至少这样做的好处是,仅更新行而不插入+删除行,这样可以节省一些I / O。
答案 1 :(得分:0)
您应该使用带有触发器的单独的摘要表,该表将包含列fk1
,fk2
和count
,其中包含check count<=N
和{{ 1}}。
在向原始表中插入行之前,应检查(fk1, fk2)
的值,如果该值已达到极限,则应首先删除最旧的行。如果您不想在应用程序中执行此操作,可以使用触发器来完成。
您必须记住:
count
行最多不能超过N
行-首先删除的行将不够; (fk1, fk2)
的多行,将会导致性能下降(并行度更差)。如果有许多(如100多个)具有相同的(fk1, fk2)
的行,那么简单的触发器只会检查行数并在插入之前删除最旧的触发器,这可能会很慢。同样,当并行执行多个插入操作时,它可能允许太多行。