我的问题
考虑一个t
包含许多来自用户的频繁更新的表,其中只有最后几个是相关的。
为了保持表的大小合理,每当插入新行时,旧行都会user_id
被删除。为了保留存档,该行也被写入t_history
.
t
和都有t_history
相同的模式,其中id
有bigserial
一个主键约束。
执行
存储过程
CREATE FUNCTION update_t_history()
RETURNS trigger
AS
$$
declare
BEGIN
-- Insert the row to the t_history table. `id` is autoincremented
INSERT INTO t_history (a, b, c, ...)
VALUES (NEW.a, NEW.b, NEW.c, ...);
-- Delete old rows from the t table, keep the newest 10
DELETE FROM t WHERE id IN (
SELECT id FROM t
WHERE user_id = NEW.user_id
ORDER BY id DESC
OFFSET 9);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
对应的插入触发器:
CREATE TRIGGER t_insertion_trigger
AFTER INSERT ON t
FOR EACH ROW
EXECUTE PROCEDURE update_t_history();
错误
触发器运行良好,但是当我在单个事务中运行几十个插入时,出现以下错误:
BEGIN
ERROR: duplicate key value violates unique constraint "t_history_pkey"
DETAIL: Key (id)=(196) already exists.
更新
- 两个表中的
id
字段(来自\d+ t
):id|bigint|not null default nextval('t_id_seq'::regclass)
"t_pkey" PRIMARY KEY, btree (id)
- PostgreSQL 版本为 9.3。
知道为什么存储过程会破坏事务中的主键约束吗?
为什么首先要
t_history.id
自动递增?如果"botht
andt_history
have the same schema"并且t.id
是串行 PK,则可以只复制整行。我还建议您只在数据修改 CTE 中将实际删除的行复制
t
到- 中。t_history
这样你就没有重叠的行(这可能是问题的一部分)。新行已在
AFTER
触发器中可见。