SQL:优化递归CTE

时间:2017-07-02 20:29:20

标签: sql sql-server common-table-expression recursive-query

示例表格结构:

EmployeeId  TeamleaderId  TopTeamleaderId   LEVEL   ParentTree    CompanyId  
1           0             0                 0       NULL          1
2           1             1                 1       2>1           1
3           2             1                 2       3>2>1         1

TeamleaderId foreignKey引用同一个表中的EmployeeId

目标: 只要在包含EmployeeId的表格中插入行,TeamleaderIdCompanyId会自动将TopTeamleaderIdLEVELParentTree填入AFTER INSERT触发器

代码:

WITH CTE AS (
  SELECT EmployeeId, TeamleaderId,0 AS [Level], CAST(EmployeeId AS varchar(100)) AS Heirarchy, TopTeamleaderId
  FROM dbo.Employee
  WHERE EmployeeId IN (SELECT EmployeeId FROM Employee WHERE TeamleaderId IS NULL 
    AND CompanyId IN(SELECT DISTINCT CompanyId FROM INSERTED))

  UNION ALL

  SELECT mgr.EmployeeId, mgr.TeamleaderId, CTE.[Level] +1 AS [Level], 
        CAST(( CAST(mgr.EmployeeId AS VARCHAR(100)) + '>' + CTE.Heirarchy) AS varchar(100)) AS Heirarchy, CTE.TopTeamleaderId
  FROM CTE
    INNER JOIN dbo.Employee AS mgr
      ON TaskCTE.EmployeeId = mgr.ParentTeamleaderId
)
UPDATE Employee SET [LEVEL] = TC.[LEVEL], ParentTree = TC.Heirarchy, TopTeamleaderId = TC.TopTeamleaderId
FROM dbo.Employee AS Employee
JOIN (SELECT * FROM CTE WHERE EmployeeId IN(SELECT DISTINCT EmployeeId FROM INSERTED) AND ParentTeamleaderId IS NOT NULL) TC
ON 
Employee.EmployeeId = TC.EmployeeId 

问题: 想象一下,公司中有100万名员工,这个查询需要很长时间才能执行。如何优化它,以便只插入插入行的父项?

1 个答案:

答案 0 :(得分:2)

递归CTE非常棒,但正如您所看到的那样,性能可能会受到更大层次结构的影响。我坚信临时表格中没有羞耻

以下将在0.784秒内生成200K点层次结构。

示例

Select EmployeeId
      ,TeamleaderId
      ,Lvl=1
      ,TopTeamleaderId = 0   
      ,ParentTree=cast(EmployeeId as varchar(500)) 
      ,CompanyID
 Into  #TempBld 
 From  Employee 
 Where TeamleaderId is null

Declare @Cnt int=1
While @Cnt<=30     --<< Set Your Max Level
    Begin
        Insert Into #TempBld 
        Select A.EmployeeId
              ,A.TeamleaderId
              ,B.Lvl+1
              ,IIF(B.Lvl=1,B.EmployeeId,B.TopTeamleaderId)
              ,concat(A.EmployeeId,'>',B.ParentTree)
              ,A.CompanyID
         From  Employee A
         Join  #TempBld B on (B.Lvl=@Cnt and A.TeamleaderId=B.EmployeeId)
        Set @Cnt=@Cnt+1
    End

--Select * from #TempBld Order by ParentTree

<强>返回

enter image description here