PostgresQL中超出堆栈深度限制(删除触发器后)
错误: 超出堆栈深度限制 提示:“在确保平台的堆栈深度限制足够后,增加配置参数“max_stack_depth”(当前为6144kB)。” 背景:PostgresQL中超出堆栈深度限制(删除触发器后),postgresql,Postgresql,错误: 超出堆栈深度限制 提示:“在确保平台的堆栈深度限制足够后,增加配置参数“max_stack_depth”(当前为6144kB)。” 背景: 一个父项可以有许多子项 该模式的设计目的是,如果删除父项,则其所有子项记录也将被删除 如果删除了子项,触发器将删除父项,然后级联删除与该父项相关的所有其他子项 这已经运行了几个月,今天我们突然发现了这个错误 我找不到无限递归,我正在考虑将堆栈深度限制加倍,看看会发生什么 注意:实际的模式比这更复杂,并且还有一些具有级联删除约束的相关表。但这是唯一
- 一个
可以有许多父项
子项
- 该模式的设计目的是,如果删除父项,则其所有子项记录也将被删除李>
- 如果删除了
,触发器将删除子项
,然后级联删除与该父项
相关的所有其他父项
子项
更新:因此我将最大堆栈深度限制提高了一倍,现在一切正常。我认为这不是一个好的解决方案,我仍然不确定如何防止将来发生这种情况。到目前为止,你知道发生了什么:
DELETE CASCADE
删除孩子1的兄弟姐妹n次
n
触发器调用。这可以解释为什么超过了堆栈深度限制,但是可以通过增加限制来修复它。如果n
越大,同样的情况也可能再次发生
或者,将触发器替换为:
CREATE TABLE parent (
parent_id VARCHAR(255) PRIMARY KEY
);
CREATE TABLE child (
parent_id VARCHAR(255) REFERENCES parent ON DELETE CASCADE,
child_id VARCHAR(255) PRIMARY KEY
);
CREATE OR REPLACE FUNCTION delete_parent()
RETURNS TRIGGER AS $$
BEGIN
DELETE FROM parent WHERE parent_id = OLD.parent_id;
RETURN NULL;
END; $$ LANGUAGE 'plpgsql';
CREATE TRIGGER delete_parent AFTER DELETE
ON child
FOR EACH ROW
EXECUTE PROCEDURE delete_parent();
并将FK约束替换为一个版本,该版本在删除级联时不包含。代码示例:
现在,要删除整个家庭,您不能像以前那样删除父级(现在FK禁止)。而是删除所有子项
也应该更快。如果父项被删除,则通过子项->父项FK的级联删除将导致所有子项被删除。你的扳机的作用正好相反。因此,一旦孩子被删除,他的父母和兄弟姐妹就会被删除。这是你的意图吗?没错。如果子项被删除,则删除父项及其所有silbingsBTW:为什么使用varchar(255)字段作为PK和FK?它实际上不是varchar(255)。服务器现在着火了,所以我只是快速编写了一个配置示例,而不是复制真正的模式。这是一个UUID。嗨@erwin谢谢你的解决方案。似乎唯一改变的是添加了DELETE FROM child,其中parent\u id=OLD.parent\u id代码>为什么这样会减少调用次数?另外,当父级被删除时,它会级联到子级,子级删除会触发再次尝试删除父级(此时不再存在)@samol:Sorry,我忘了添加基本细节:从FK约束中删除ON DELETE CASCADE
。但我需要ON DELETE CASCADE触发器,因为有时我会删除父级,我需要删除该父级cascade@samol:您可以删除任何子对象以获得相同的效果。此外,我不完全确定您的问题是否由您提到的其他触发器/约束引起。
CREATE OR REPLACE FUNCTION delete_family()
RETURNS TRIGGER AS
$func$
BEGIN
DELETE FROM child WHERE parent_id = OLD.parent_id;
DELETE FROM parent WHERE parent_id = OLD.parent_id; -- done after 1st call
RETURN NULL;
END
$func$ LANGUAGE plpgsql; -- don't quote the language name!
CREATE TRIGGER delete_family
AFTER DELETE ON child
FOR EACH ROW EXECUTE PROCEDURE delete_family();