PostgresQL中超出堆栈深度限制(删除触发后)

时间:2014-08-23 18:33:07

标签: postgresql

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();

错误:

stack depth limit exceeded 提示:'确保平台的堆栈深度限制足够后,增加配置参数“max_stack_depth”(目前为6144kB)。

背景:

  • parent可以有多个children
  • 架构的设计使得如果删除parent,则还会删除其所有子记录。
  • 如果删除child,则触发器会删除parent,然后级联删除与该children相关的所有其他parent

这已经工作了几个月,今天我们突然开始出现这个错误。

我无法找到可能存在无限递归的情况,我正在考虑将堆栈深度限制加倍,看看会发生什么。

注意:实际模式比这更复杂,并且有一些更多相关的表具有CASCADE删除约束。但这是唯一的触发因素。

UPDATE :所以我将max_stack_depth限制加倍,现在没问题了。我不认为这是一个很好的解决方案,我仍然不确定如何防止将来发生这种情况。

1 个答案:

答案 0 :(得分:2)

到目前为止,你发生了什么:

  1. 删除child1。
  2. 触发删除父级。
  3. n删除child1的 DELETE CASCADE 兄弟姐妹。
  4. 调用相同的触发器 n 次。
  5. 不再有兄弟姐妹了。
  6. 没有无限循环,但仍然 n 调用触发器。这可以解释为什么超出了堆栈深度限制,但您可以通过增加限制来修复它。同样的情况可能会再次发生n

    作为替代方案,请使用以下命令替换您的触发器:

    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();
    

    并使用版本 替换FK约束而不使用 ON DELETE CASCADE。代码示例:

    现在,对于DELETE整个家庭,你不能像以前一样删除父母(现在被FK禁止)。而是DELETE任何孩子。

    也应该更快。