PostgreSQL递归CTE百万大小树的动态排序分页选择
我的目标是创建一个查询,通过控制每个深度返回的项目的深度和数量(按排名降序排序,排名经常变化),我可以在其中检索树 即 给我从节点id 4开始的树,最大深度为5,从该节点开始,每个级别最多有5个子节点,按秩降序排列 所以我有一个树形结构:PostgreSQL递归CTE百万大小树的动态排序分页选择,postgresql,recursion,tree,recursive-query,Postgresql,Recursion,Tree,Recursive Query,我的目标是创建一个查询,通过控制每个深度返回的项目的深度和数量(按排名降序排序,排名经常变化),我可以在其中检索树 即 给我从节点id 4开始的树,最大深度为5,从该节点开始,每个级别最多有5个子节点,按秩降序排列 所以我有一个树形结构: CREATE TABLE thingtree ( id uuid NOT NULL, parent_id uuid, text character varying(2048) NOT NULL, rank integer NOT NULL DE
CREATE TABLE thingtree
(
id uuid NOT NULL,
parent_id uuid,
text character varying(2048) NOT NULL,
rank integer NOT NULL DEFAULT 0,
CONSTRAINT thingtree_pkey PRIMARY KEY (id),
CONSTRAINT thingtree_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES thingtree (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
我想按id选择一个节点,然后获取它的所有子节点,每个深度都有一个可配置的记录限制,并按等级排序,这是经常变化的
所以我决定创建一些数据:
CREATE EXTENSION "uuid-ossp";
CREATE FUNCTION build_tree (parent_id uuid,max_depth integer,current_depth integer,max_direct_children integer) RETURNS boolean AS $$
DECLARE
new_id uuid := uuid_generate_v4();
BEGIN
IF current_depth >= max_depth THEN
RETURN 0;
END IF;
insert into thingtree VALUES (new_id, parent_id,'test',current_depth + 1);
FOR i IN 0..(max_direct_children - 1) LOOP
PERFORM build_tree(new_id,max_depth,current_depth + 1, max_direct_children);
END LOOP;
RETURN 0;
END;
$$ LANGUAGE plpgsql;
然后我使用这个函数生成一个5层的树,每个层有6个子层
select build_tree(NULL ,5, 0 ,6);
运行上述功能可能需要约20秒
接下来,我尝试递归地选择数据:
WITH RECURSIVE thingtrees AS (
SELECT tt.id,1::INT AS depth, tt.parent_id, tt.text, tt.rank FROM thingtree as tt WHERE id = '207f7c55-1c68-4f0e-9493-416b84b6a0a4'
UNION ALL
SELECT st.id, tts.depth + 1 AS depth, st.parent_id, st.text, st.rank
FROM
thingtrees as tts
JOIN
thingtree st
on (tts.id = st.parent_id)
WHERE tts.depth <= 5 order by st.rank
)
SELECT *
FROM thingtrees
现在深度很好,它知道不能超过5,但问题是我只希望树中每个节点级别最多有5个直接子节点,但结果返回6,因为我没有限制它
问题是如果我从CTE限制递归联合:
WITH RECURSIVE thingtrees AS (
SELECT tt.id,1::INT AS depth, tt.parent_id, tt.text, tt.rank FROM thingtree as tt WHERE id = '207f7c55-1c68-4f0e-9493-416b84b6a0a4'
UNION ALL
(SELECT st.id, tts.depth + 1 AS depth, st.parent_id, st.text, st.rank
FROM
thingtrees as tts
JOIN
thingtree st
on (tts.id = st.parent_id)
WHERE tts.depth <= 5 order by st.rank limit 5)
)
SELECT *
FROM thingtrees
这里的问题是它只返回树的前5个子节点,而不是每个深度的5个子节点。复制了您的示例,并从每个深度获得了21行5个子节点。这不是人们所期望的吗?您确定手动提供的id是根节点吗?序列仍处于关闭状态,order by st.rank仅按秩排序整个深度。