계층 구조 링크 (parent_id, child_id)의 그래프를 나타내는 테이블이 있습니다. 테이블에 부모, 자식 및 둘 모두에 대한 인덱스가 있습니다. 그래프에 루프가 포함되어있을 수 있으므로이를 확인해야합니다 (또는 루프를 제거하기 위해 루프를 찾아야 할 수도 있습니다).postgresql은 재귀 적 쿼리에 대한 인덱스를 무시합니다.
그리고 노드의 모든 부모를 재귀 적으로 쿼리해야합니다. 내가이 쿼리를 사용이를 위해 은 (보기에 저장하도록되어) :이 쿼리 포스트 그레스를 들어
WITH RECURSIVE recursion(parent_id, child_id, node_id, path) AS (
SELECT h.parent_id,
h.child_id,
h.child_id AS node_id,
ARRAY[h.parent_id, h.child_id] AS path
FROM hierarchy h
UNION ALL
SELECT h.parent_id,
h.child_id,
r.node_id,
ARRAY[h.parent_id] || r.path
FROM hierarchy h JOIN recursion r ON h.child_id = r.parent_id
WHERE NOT r.path @> ARRAY[h.parent_id]
)
SELECT parent_id,
child_id,
node_id,
path
FROM recursion
where node_id = 883
매우 훌륭한 계획을 사용하는 것입니다 :
"CTE Scan on recursion (cost=2703799682.88..4162807558.70 rows=324223972 width=56)"
" Filter: (node_id = 883)"
" CTE recursion"
" -> Recursive Union (cost=0.00..2703799682.88 rows=64844794481 width=56)"
" -> Seq Scan on hierarchy h (cost=0.00..74728.61 rows=4210061 width=56)"
" -> Merge Join (cost=10058756.99..140682906.47 rows=6484058442 width=56)"
" Merge Cond: (h_1.child_id = r.parent_id)"
" Join Filter: (NOT (r.path @> ARRAY[h_1.parent_id]))"
" -> Index Scan using hierarchy_idx_child on hierarchy h_1 (cost=0.43..256998.25 rows=4210061 width=16)"
" -> Materialize (cost=10058756.56..10269259.61 rows=42100610 width=48)"
" -> Sort (cost=10058756.56..10164008.08 rows=42100610 width=48)"
" Sort Key: r.parent_id"
" -> WorkTable Scan on recursion r (cost=0.00..842012.20 rows=42100610 width=48)"
이 포스트 그레스 같이하지 않는 것 같다 첫 번째 재귀 서브 쿼리에서 node_id의 외부 필터가 child_id에 적용된다는 것을 이해해야합니다.
나는 아주 잘못하고 있다고 생각합니다. 그러나 정확히 어디에서? 여기
WITH RECURSIVE recursion(parent_id, child_id, node_id, path) AS (
SELECT h.parent_id,
h.child_id,
h.child_id AS node_id,
ARRAY[h.parent_id, h.child_id] AS path
FROM hierarchy h
WHERE node_id = 883
UNION ALL
SELECT h.parent_id,
h.child_id,
r.node_id,
ARRAY[h.parent_id] || r.path
FROM hierarchy h JOIN recursion r ON h.child_id = r.parent_id
WHERE NOT r.path @> ARRAY[h.parent_id]
)
SELECT parent_id,
child_id,
node_id,
path
FROM recursion
일반적으로 상위 노드 (부모 없음) 또는 리프 노드 (자식 없음) 또는 관심이있는 특정 레코드 # 조건이 UNION의 첫 번째 부분에 있습니다. 체인 스타터로서의 모든 기록. – wildplasser
유니온의 첫 번째 쿼리는 테이블의 ** 모든 ** 행을 검색합니다. 인덱스가 도움이되지 않습니다. –
postgres가 외부 필터를 내부 하위 쿼리와 병합 할 수 있기를 바랍니다. 나는 너무 낙관적 인 것처럼 보인다. – qMax