2016-07-04 11 views
0

深いツリー構造を表す親子関係を持つテーブルがあります。CTE SQL Serverクエリのパフォーマンスの問題

データを照会するのにCTEのビューを使用していますが、パフォーマンスが低い(下記のコードと実行計画を参照)。

パフォーマンスを向上させる方法はありますか?

WITH cte (ParentJobTypeId, Id) AS 
( 
    SELECT 
     Id, Id 
    FROM  
     dbo.JobTypes 

    UNION ALL 

    SELECT 
     e.Id, cte.Id 
    FROM  
     cte 
    INNER JOIN 
     dbo.JobTypes AS e ON e.ParentJobTypeId = cte.ParentJobTypeId 
) 
SELECT 
    ISNULL(Id, 0) AS ParentJobTypeId, 
    ISNULL(ParentJobTypeId, 0) AS Id 
FROM  
    cte 

CTE Execution Plan

+0

私は、いくつのレベルの深さを意味するのですか? – Lamak

+0

ツリーはユーザーによって作成されているので、私は約5-9を推測しています。 – Burt

+1

700,000ポイントの階層?どのくらいの頻度で変更されますか? –

答えて

3

範囲キーを使用しての簡単な例。私は前に述べたように階層が127K点及びCTEはビルド

15のレベルが深いいくつかのセクションであった、

Declare @Table table(ID int,ParentID int,[Status] varchar(50)) 
Insert @Table values 
(1,101,'Pending'), 
(2,101,'Complete'), 
(3,101,'Complete'), 
(4,102,'Complete'), 
(101,null,null), 
(102,null,null) 


;With cteOH (ID,ParentID,Lvl,Seq) 
as (
    Select ID,ParentID,Lvl=1,cast(Format(ID,'000000') + '/' as varchar(500)) from @Table where ParentID is null 
    Union All 
    Select h.ID,h.ParentID,cteOH.Lvl+1,Seq=cast(cteOH.Seq + Format(h.ID,'000000') + '/' as varchar(500)) From @Table h INNER JOIN cteOH ON h.ParentID = cteOH.ID 
    ), 
    cteR1 as (Select ID,Seq,R1=Row_Number() over (Order by Seq) From cteOH), 
    cteR2 as (Select A.ID,R2 = max(B.R1) From cteOH A Join cteR1 B on (B.Seq Like A.Seq+'%') Group By A.ID) 
    Select B.R1 
      ,C.R2 
      ,A.Lvl 
      ,A.ID 
      ,A.ParentID 
    Into #TempHier 
    From cteOH A 
    Join cteR1 B on (A.ID=B.ID) 
    Join cteR2 C on (A.ID=C.ID) 

    Select * from #TempHier 

    Select H.R1 
      ,H.R2 
      ,H.Lvl 
      ,H.ID 
      ,H.ParentID 
      ,Total = count(*) 
      ,Complete = sum(case when D.Status = 'Complete' then 1 else 0 end) 
      ,Pending = sum(case when D.Status = 'Pending' then 1 else 0 end) 
      ,PctCmpl = format(sum(case when D.Status = 'Complete' then 1.0 else 0.0 end)/count(*),'##0.00%') 
    From #TempHier H 
    Join (Select _R1=B.R1,A.* From @Table A Join #TempHier B on A.ID=B.ID) D on D._R1 between H.R1 and H.R2 
    Group By H.R1 
      ,H.R2 
      ,H.Lvl 
      ,H.ID 
      ,H.ParentID 
    Order By 1 

戻りのがHIER結果は(同様に索引付け)テーブルに格納されるであろうと仮定する今の#Tempテーブルのhier。 R1とR2に注目して、これらをレンジキーと呼んでいます。データ(再帰なし)これらのキーを介して選択して集約することができる

R1 R2 Lvl ID ParentID 
1 4 1 101 NULL 
2 2 2 1 101 
3 3 2 2 101 
4 4 2 3 101 
5 6 1 102 NULL 
6 6 2 4 102 

非常に単純な例:HIERまでデータを圧延図解します。

R1 R2 Lvl ID ParentID Total Complete Pending PctCmpl 
1 4 1 101 NULL  4  2   1  50.00% 
2 2 2 1 101   1  0   1  0.00% 
3 3 2 2 101   1  1   0  100.00% 
4 4 2 3 101   1  1   0  100.00% 
5 6 1 102 NULL  2  1   0  50.00% 
6 6 2 4 102   1  1   0  100.00% 

範囲キーの本当の美しさは、あなたがIDを知っていれば、あなたはそれが存在する場所(すべての子孫と先祖を)知っています。

+1

127Kポイントの魔力は12秒かかります。私は770Kに話すことができません –

+1

助けがあれば、より堅牢な例がここにありますhttp://stackoverflow.com/questions/37954697/sql-server-hierarchy-with-parent-id-and-child-id/37992828# 37992828 –

+0

ありがとうございます。 PctCmplとR1とR2の合計は何を表していますか? (無駄な質問には申し訳ありません) – Burt

関連する問題