2016-07-04 160 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

700k點層次結構?它多久改變一次? –

回答

3

使用範圍的鍵的一個簡單的例子。正如我前面提到的,等級分別爲127K點和一些部分,其中深15級

CTE的構建,讓我們假設票數結果將被存儲在一個表中(索引爲好)

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 

返回現在在#Temp表中的更高層。注意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 

非常簡單的例子來選擇和聚合:說明了滾動數據向上票數。

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

謝謝。 Total Complete Pending PctCmpl以及R1和R2代表什麼? (對於愚蠢的問題抱歉) – Burt