2010-04-26 5 views
8

약 50,000 개의 행을 포함하는 테이블 (dbo. [Message])에 hierarchyID를 구현하려고합니다 (이후 크게 증가 할 것입니다). 그러나 약 25 개의 결과를 검색하는 데 30-40 초가 소요됩니다.SQL Server 계층 구조 깊이 우선 순위 성능에 대한 질문

루트 노드는 고유성을 제공하기위한 필러이므로 모든 후속 행은 그 더미 행의 하위 노드입니다.

우선 테이블 깊이를 탐색 할 수 있어야하며 hierarchyID 열 (dbo. [Message] .MessageID)을 클러스터링 기본 키로 만들고 계산 된 smallint (dbo. [Message] .Hierarchy) 노드의 레벨을 저장합니다.

사용법 : .Net 응용 프로그램은 hierarchyID 값을 통해 데이터베이스에 전달되며 모든 노드 (해당되는 경우)와 그 노드의 부모 (필러이므로 루트 이외에)를 검색 할 수 있기를 원합니다.

내가 사용하고있는 쿼리의 단순화 된 버전 : 내가 이해에서

@MessageID hierarchyID /* passed in from application */ 

SELECT 
m.MessageID, m.MessageComment 

FROM 
dbo.[Message] as m 

WHERE 
m.Messageid.IsDescendantOf(@MessageID.GetAncestor((@MessageID.GetLevel()-1))) = 1 

ORDER BY 
m.MessageID 

는, 인덱스 힌트없이 자동으로 감지해야한다.

포럼 검색에서 너비 우선 색인을 처리 할 때 색인 힌트를 사용하는 사람들을 보았지만 깊이 우선 상황에서는이 응용 프로그램을 관찰하지 않았습니다. 그게 내 시나리오에 대한 적절한 접근 방법 이겠니?

지난 며칠 동안이 문제에 대한 해결책을 찾으려고했지만 아무 소용이 없었습니다. 나는 이것이 도움이 될 수있어서 매우 감사 할 것이고, 이것이 나의 첫 번째 게시물이기 때문에, 이것이 'noobish'질문으로 간주된다면 사전에 사과 할 것이고, 나는 MS 문서를 읽고 무수한 포럼을 수색했지만 간결한 설명 문제의

+0

그건 그렇고, 당신은 가지고있는 쿼리? 작성된 것처럼 항상 테이블 전체에서 모든 노드를 선택합니다. '@ MessageID.GetAncestor (@ MessageID.GetLevel() - 1)'은 루트까지 모든 것을 가져온 다음 자손, 즉 모든 것을 선택합니다. 그래서 너무 느립니다. – Aaronaught

+0

그냥 명확히하기 위해서 : 내 상황은 깊이 우선 색인 생성을 사용해야합니다. 혼란에 대해 유감스럽게 생각합니다. (색인 힌트를 사용하여 사람들이 제안한 예를 제공하기 위해 폭을 먼저 나타냅니다.) – ObjectiveCat

답변

2

찾을 해결 방법 : http://connect.microsoft.com/SQLServer/feedback/details/532406/performance-issue-with-hierarchyid-fun-isdescendantof-in-where-clause#

그냥 내가 응용 프로그램에서 전달 된 heirarchyID 시작하고 내 목표는 일체의 그 값의 친척 (모두 조상과 후손를) 검색 할 수 있음을 상기. WHERE 조항이 변경되었습니다

declare @topNode hierarchyid = (select @messageID.GetAncestor((@messageID.GetLevel()-1))) 
declare @topNodeParent hierarchyid = (select @topNode.GetAncestor(1)) 
declare @leftNode hierarchyid= (select @topNodeParent.GetDescendant (null, @topNode)) 
declare @rightNode hierarchyid= (select @topNodeParent.GetDescendant (@topNode, null)) 

:

내 특정 예에서

, 나는 SELECT 문 앞에 다음과 같은 선언을 추가했다

messageid.IsDescendantOf(@topNode)=1 AND (messageid > @leftNode) AND (messageid < @rightNode) 

질의 성능 향상이 매우 중요하다 :

전달 된 모든 결과에 대해 검색 시간은 평균 20ms (120에서 420)였습니다.

25 개의 값을 쿼리 할 때 이전에 모든 관련 노드를 반환하는 데 25-35 초가 걸렸습니다. 어떤 경우에는 각 값에 많은 친척이 있고 어떤 경우에는 아무 것도 없었습니다. 이제 2 초 밖에 걸리지 않습니다.

이 사이트와 다른 사이트에서이 문제에 기여해 주신 모든 분들께 진심으로 감사드립니다.

8

깊이 우선 또는 너비 우선 검색을 최적화하려고하는지 여부는 완전히 명확하지 않습니다. 질문은 깊이 우선을 제안하지만, 끝에있는 주석은 폭 우선에 관한 것입니다.

깊이 우선 필요한 인덱스가 모두 있습니다 (hierarchyid 색인 만).

ALTER TABLE Message 
ADD [Level] AS MessageID.GetLevel() 

CREATE INDEX IX_Message_BreadthFirst 
ON Message (Level, MessageID) 
INCLUDE (...) 

(클러스터되지 않은 인덱스에 대해 가장 가능성이 INCLUDE을해야합니다 - 그렇지를 들어 폭 우선, 그것은 가 계산 level 열을 만들 단지에 충분하지, 당신은 너무 인덱스를로가 SQL Server는 대신 클러스터 된 인덱스 검색을 수행 할 수 있습니다. 노드의 상위 노드을 찾으려면 약간 다른 점을 찍고 싶습니다. 이 검색은 번개처럼 빠르게 할 수 있습니다. 왜냐하면 - 여기서 hierarchyid에 대해 멋진 점이 있습니다. 각 노드는 이미 모든 조상을 "포함하고 있습니다".

나는 가능한 한 빨리이 문제를 확인하기 위해 CLR 기능을 사용하지만 재귀 CTE와 함께 할 수 있습니다

CREATE FUNCTION dbo.GetAncestors 
(
    @h hierarchyid 
) 
RETURNS TABLE 
AS RETURN 
WITH Hierarchy_CTE AS 
(
    SELECT @h AS id 

    UNION ALL 

    SELECT h.id.GetAncestor(1) 
    FROM Hierarchy_CTE h 
    WHERE h.id <> hierarchyid::GetRoot() 
) 
SELECT id FROM Hierarchy_CTE 

을 이제, 조상과 후손을 모두 얻을이처럼 사용할 수 :

DECLARE @MessageID hierarchyID /* passed in from application */ 

SELECT m.MessageID, m.MessageComment 
FROM Message as m 
WHERE m.MessageId.IsDescendantOf(@MessageID) = 1 
OR m.MessageId IN (SELECT id FROM dbo.GetAncestors(@MessageID.GetAncestor(1))) 
ORDER BY m.MessageID 

성능상의 문제를 해결해야합니다.여기

+0

죄송합니다. 혼란, 깊이 우선은 실제로 내가 무엇을했는지입니다! 제안 해 주셔서 감사합니다. 바로 시도해 보겠습니다. – ObjectiveCat

+0

단지에 대한 테스트를 위해, 나는 모두 나가던 MessageID.GetAncestor @ 제거한 : m.MessageId.IsDescendantOf (@MessageID) = 1 에서 절 내가 그 시저를 실행했을 때, 탐색 시간 (150)을 사이에 여전히 ~ 420ms (결과 당), 이는 매우 느립니다. 성능이 우선적인데 CLR에 대해 완전히 익숙하지 않지만 최상의 성능을 제공하려면 구현 방법을 배우고 싶습니다. 시작할 위치에 따른 제안 사항은 무엇입니까? – ObjectiveCat

+0

@AndalusianCat : CLR 버전은 상위 쿼리 용입니다. 'IsDescendantOf'를 사용하는 것이 느리다면 실제 쿼리, 테이블 스키마 (인덱스 포함) 및 실행 계획을 게시하십시오. 'hierarchyid' 쿼리는 일반적으로 그것보다 훨씬 빠릅니다. – Aaronaught