조상으로부터 후손의 깊이를 계산해야합니다. 레코드에가 있으면 object_id = parent_id = ancestor_id
루트 노드 (조상)로 간주됩니다. WITH RECURSIVE
PostgreSQL 9.4 에서 쿼리를 실행 하려고했습니다 .
데이터 또는 열을 제어하지 않습니다. 데이터 및 테이블 스키마는 외부 소스에서 가져옵니다. 테이블은 지속적으로 성장하고 있습니다 . 현재 하루에 약 30k 레코드가 있습니다. 트리의 모든 노드가 누락 될 수 있으며 어느 시점에서 외부 소스에서 가져옵니다. 일반적으로 created_at DESC
순서대로 가져 오지만 데이터는 비동기 백그라운드 작업으로 가져옵니다.
처음에는이 문제에 대한 코드 솔루션이 있었지만 이제 5 백만 개 이상의 행이 있으므로 완료하는 데 거의 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로 설정됩니다. A는 경우가 있습니다 parent_id
아직 뽑아되지 않았을 수도. 이 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
쿼리 결과는 생성 열을 올바른 깊이로 업데이트해야합니다.
나는 SO에 관한이 관련 질문에 대한 답변 에서 일하기 시작했습니다 .
update
재귀 CTE의 결과와 함께 테이블 을 원 하십니까?