我需要根据祖先计算后代的深度。当记录具有时object_id = parent_id = ancestor_id
,它将被视为根节点(祖先)。我一直在尝试使WITH RECURSIVE
查询与PostgreSQL 9.4一起运行。
我不控制数据或列。数据和表架构来自外部来源。桌子在不断增长。目前每天约有3万条记录。树中的任何节点都可能丢失,并且它们有时会从外部源中拉出。通常按created_at DESC
顺序提取它们,但是使用异步后台作业提取数据。
最初,我们有一个解决此问题的代码,但现在有5M +行,需要近30分钟才能完成。
表定义和测试数据示例:
CREATE TABLE objects (
id serial NOT NULL PRIMARY KEY,
customer_id integer NOT NULL,
object_id integer NOT NULL,
parent_id integer,
ancestor_id integer,
generation integer NOT NULL DEFAULT 0
);
INSERT INTO objects(id, customer_id , object_id, parent_id, ancestor_id, generation)
VALUES (2, 1, 2, 1, 1, -1), --no parent yet
(3, 2, 3, 3, 3, -1), --root node
(4, 2, 4, 3, 3, -1), --depth 1
(5, 2, 5, 4, 3, -1), --depth 2
(6, 2, 6, 5, 3, -1), --depth 3
(7, 1, 7, 7, 7, -1), --root node
(8, 1, 8, 7, 7, -1), --depth 1
(9, 1, 9, 8, 7, -1); --depth 2
请注意,这object_id
不是唯一的,但组合(customer_id, object_id)
是唯一的。
运行这样的查询:
WITH RECURSIVE descendants(id, customer_id, object_id, parent_id, ancestor_id, depth) AS (
SELECT id, customer_id, object_id, parent_id, ancestor_id, 0
FROM objects
WHERE object_id = parent_id
UNION
SELECT o.id, o.customer_id, o.object_id, o.parent_id, o.ancestor_id, d.depth + 1
FROM objects o
INNER JOIN descendants d ON d.parent_id = o.object_id
WHERE
d.id <> o.id
AND
d.customer_id = o.customer_id
) SELECT * FROM descendants d;
我希望将generation
列设置为计算出的深度。添加新记录时,将生成列设置为-1。在某些情况下,parent_id
可能尚未将a 拉出。如果parent_id
不存在,则应将生成列设置为-1。
最终数据应如下所示:
id | customer_id | object_id | parent_id | ancestor_id | generation
2 1 2 1 1 -1
3 2 3 3 3 0
4 2 4 3 3 1
5 2 5 4 3 2
6 2 6 5 3 3
7 1 7 7 7 0
8 1 8 7 7 1
9 1 9 8 7 2
查询的结果应该是将生成列更新为正确的深度。
update
递归CTE的结果与表格一起使用吗?