让我解释一下我的设想。
我有一个包含550万条记录的简单表,结构很简单。
relations
------------
id
parent_id
name
我有一个递归函数来获取一个节点的所有子节点id;这个函数在任何情况下都能正常工作,这不是问题所在
CREATE OR REPLACE FUNCTION children_ids(id INTEGER)
RETURNS INT[]
LANGUAGE plpgsql
AS
$$
DECLARE
ids INT[];
r RECORD;
BEGIN
FOR r IN WITH RECURSIVE t
AS
(
SELECT *
FROM relations sa
WHERE sa.id = id
UNION ALL
SELECT next.*
FROM t prev
JOIN relations next ON (next.parent_id = prev.id)
)
SELECT t.id FROM t
LOOP
ids := ids || r.id;
END LOOP;
RETURN ids;
END
$$;
然后,我需要查询另一个表,以获取函数返回的任何子id中的记录数:
我要执行的查询是:
SELECT COUNT(p.*) FROM books AS p WHERE p.id = ANY(children_ids(20));
但由于超时,它失败了。奇怪的是,在我的localhost中,这个相同的查询工作正常,数据库被克隆,PostgreSQL版本是相同的。
我已经测试了另一种变体,结果如下:
SELECT children_ids(20);
-- WORKS: {20}
SELECT COUNT(p.*) FROM books AS p WHERE p.id = ANY(children_ids(20));
-- FAILS: TIMEOUT
SELECT COUNT(*) FROM books AS p WHERE p.id = ANY(children_ids(20));
-- FAILS: TIMEOUT
SELECT * FROM books AS p WHERE p.id = ANY(children_ids(20));
-- FAILS: TIMEOUT
SELECT COUNT(p.*) FROM books AS p WHERE p.id = ANY(ARRAY[20]);
-- WORKS: 0
SELECT COUNT(p.*) FROM books AS p WHERE p.id IN (20);
-- WORKS: 0
SELECT COUNT(*) FROM books AS p WHERE p.id IN (20);
-- WORKS: 0
你知道这里会发生什么吗
1条答案
按热度按时间krcsximq1#
您的数据中可能存在循环,因此您的递归会进入无限循环。有关如何打破循环的信息,请参阅文档。使用PostgreSQL v14或更高版本,最简单的方法是