2012-04-13 3 views
2

공통 테이블 식을 사용하여 메뉴 위로 계층 경로를 작성하는 저장 프로 시저가 있습니다 (부모 메뉴 -> 하위 메뉴 -> 하위 하위 메뉴 -> 같은 것을 표시 할 수 있습니다) ...)CTE 성능에 합치기

정말 재귀 적 CTE에서 얻은 정보를 내가 원하는 정보에 넣을 때 문제가된다. 내 데이터에서 CTE로 내부 조인을 수행하고 계층 적 경로를 가져옵니다. ~ 300 행을 반환하는 항목의 경우 저장 프로 시저의 평균 소요 시간은 15-20 초입니다.

CTE의 결과를 임시 테이블에 삽입하고이를 기반으로 조인을 수행하면 절차가 1 초 이내에 완료됩니다.

CTE만을 사용하여 가입하는 데 너무 오래 걸리는 이유 또는 CTE를 어떤 식 으로든 오용하는 이유가 궁금합니다.

** 편집이 저장 프로 시저를 본질적으로

With Hierarchical_Path (Menu_ID, Parent_ID, Path) 

As 
(
Select 
    EM.Menu_Id, Parent_ID, 
      Convert(varchar(max), 
      EM.Description) as Path 
From 
    Menu EM 
Where 
--EM.Topic_No is null 
    EM.Parent_ID = 0 and EM.Disabled = 0 
Union All 
Select 
    EM.Menu_ID, 
      EM.Parent_ID, 
      Convert(Varchar(max),E.Path + ' -> ' + EM.Description) as Path 
From 
    Menu EM 
Inner Join 
    Hierarchical_Path E 
On 
    EM.Parent_ID = E.Menu_ID  
) 

SELECT distinct 
    EM.Description 
    ,EMS.Path 
FROM 
    dbo.Menu em 
INNER JOIN 
    Hierarchical_Path EMS 
ON 
    EMS.Menu_ID = em.Menu_Id 
    2 more INNER JOINs 
    2 Left Joins 
    WHERE Clause 

나는 성능이 약 20 초합니다 (CTE에 가입)이 같은 쿼리를 실행합니다.

임시 테이블에 CTE 결과를 삽입하고 결합하면 성능이 즉각적으로 향상됩니다.

내 쿼리를 좀 더 자세히 살펴보면 where 절에 매달린 것처럼 보입니다. 제 질문은 정확히 CTE가 실행되고 메모리에 저장되는 시점에 더 가깝습니다. 나는 그것이 한 번 부름을 받았고 그 다음에 기억 속에 갇혀 있다고 가정하면서 달리고 있었지만 어떤 경우에는 그것이 여러 번 불릴 수 있었습니까?

+3

비교 가능한 검색어를 여기에 표시하십시오. – Yuck

+0

재귀 CTE는 상대적으로 느리고 다중 테이블 스캔을 포함 할 수 있습니다. CTE에 관련된 표 [s]와이 표의 대략적인 행 수에 대한 자세한 내용을 제공하지 않는 한, 귀하의 질문에 대답하는 것이 불가능하다고 생각합니다. – a1ex07

+0

@ a1ex07 일반적으로 말할 수는 없습니다. 비 재귀 CTE는보기와 동일합니다. 쿼리 컴파일 중에 완전히 사라집니다. 재귀적인 경우에는 완전히 당신이하는 일에 달려 있습니다. – usr

답변

1

차이점은 CTE가 유지되지 않으며 임시 테이블이 (적어도 세션의 경우) 있다는 것입니다. 비 지속 열에 가입하면 SQL에 이미 사전 평가 된 임시 테이블의 동일한 열과 비교하여 데이터에 대한 통계가 전혀 없다는 것을 의미합니다. 기본적으로 임시 테이블은 사용자가 사용할 캐시를 캐시하므로 SQL Server는이를 더 잘 최적화 할 수 있습니다. 함수 나 테이블 변수의 결과를 결합 할 때도 동일한 문제가 발생합니다.

내 생각 엔 CTE 실행 계획이 임시 테이블에서 여러 스레드를 사용할 수있는 동안 단일 스레드로 실행하고있는 것 같습니다. 쿼리를 실행하고 각 연산자에서 반대 방향을 가리키는 두 개의 수평 화살표를 찾을 때 실제 실행 계획을 포함하여이를 확인할 수 있습니다. 그것은 병렬 처리를 나타냅니다.

P. - "set statistics io on"및 "set statistics time on"을 설정하여 실행 기간에 관계없이 쿼리 실행의 실제 비용이 동일한 지 확인하십시오.