2011-05-02 5 views
10

나는 간단한 질문이 있습니다. 어떻게 든 나는 확실한 답을 찾을 수 없었습니다.PostgreSQL 재시작 성능이

WITH RECURSIVE 구문은 PostgreSQL에서 어느 정도 최적화 되었습니까? 즉, 일련의 비 재귀 쿼리에 대한 구문 설탕 일 뿐이며 복잡한 의미에도 불구하고 전체적으로 최적화 된 단일 구문에 더 가깝습니다. 후속 질문 - 이러한 종류의 구문을 최적화하는 것이 어느 정도 가능합니까? 물론이 문제에 대한 구체적인 데이터가 가장 환영받을 것입니다.

답변

4

내 경험에 따르면 실제로는 매우 잘 최적화되어 있습니다.

체크 아웃에 의해 생성 당신의 쿼리에 대한 실행 계획 ANALYZE 설명하고 당신은 정말 얼마나 "비용"을 참조하십시오 (다음 작성된 자기 재귀 함수에 그 예를 비교) 나는했습니다

+1

언어 수준에서'WITH RECURSIVE '를 사용하는 모든 이유는 데이터베이스가 사용자가하려는 일을 알고 사용자의 의도에 따라 행동 할 수 있도록하기 위해서입니다. –

+0

@mu 네, 저도 그렇게 생각합니다. 그러나 데이터베이스 레벨에서 인덱스 등을 사용하여 어떻게 최적화 할 수 있는지는 분명하지 않습니다. 일부 작업은 일반적으로 어렵습니다. 제안이 끝나면 내가 마자 내 결과를 게시 할 것입니다. – julkiewicz

+0

@julkiewicz 전이 클로저 테이블은 사실 이러한 쿼리에 대한 인덱스입니다. 비슷한 기술을 사용하는 색인 ​​유형을 제공 할 수없는 이유는 없습니다. – EricS

16

것 포인트까지 최적화 된 것으로 나타났습니다.

다양한 하위 쿼리가 예상대로 재사용되고 개별적으로 최적화되며 Postgres는 다른 쿼리와 마찬가지로 후자를 최적화합니다.

필자의 주요 불만은 가능한 경우 CTE에 제약 조건을 주입하지 않는다는 것과 관계가 있습니다. 예를 들어

:

with recursive 
parents as (
select node.id, 
     node.parent_id 
from nodes as node 
union all 
select node.id, 
     parent.parent_id 
from parents as node 
join nodes as parent on parent.id = node.parent_id 
) 
select parent_id 
from parents 
where id = 2; 

포스트 그레스가 이상적으로 이해하는 것, 위의, 그게 할 수있는 ( 같이 node.id 이후 을 반환) :

with recursive 
parents as (
select node.id, 
     node.parent_id 
from nodes as node 
where id = 2 
union all 
select node.id, 
     parent.parent_id 
from parents as node 
join nodes as parent on parent.id = node.parent_id 
) 
select parent_id 
from parents; 

을 ... 기본 키에서 색인 스캔을 사용하십시오. 실제로 실제로 CTE가 지시하면 정확하게 수행 할 것입니다. 모든 행에 대해 모든 부모를 반복적으로 가져오고, 필요한 경우 이름이 지정되지 않은 임시 테이블에 결과 세트를 놓은 다음 결과 세트에서 각 행을 확인하십시오. id = 2.

즉, CTE는 돌아 오는 "원본"테이블/행/열 집합의 추적을 유지하지 않습니다. 이것이 최적화 될 때까지 재귀 쿼리에 대한 뷰를 생성하는 것은 최선의 방법입니다.

create function parents(id int) as returns table (id int) $$ 
    with recursive 
    parents as (
    select node.id, 
      node.parent_id 
    from nodes as node 
    where id = $1 
    union all 
    select node.id, 
      parent.parent_id 
    from parents as node 
    join nodes as parent on parent.id = node.parent_id 
    ) 
    select parent_id 
    from parents; 
$$ language sql stable strict rows 5 cost 1; 

또 다른 문제는 (사실, 매우 같은 이유로) 재귀 CTE를 가진 FOR UPDATE를 사용할 수있다 :

한편의 좋은 해결 방법은 대신 SQL 함수를 만드는 것입니다.

+0

이 답변의 나이를 감안할 때 설명하신 행동의 최근 변경 사항에 대해 알고 있습니까? –

+0

@OliverSalzburg : 정직하게 생각하지 못하지만 답변에서 쿼리의 쿼리 계획을 비교하여 테스트하는 것이 합리적으로 쉽습니다. –