【问题标题】:SQL: Optimizing Recursive CTESQL:优化递归 CTE
【发布时间】:2017-07-02 20:29:20
【问题描述】:

示例表结构:

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

TeamleaderIdforeignKey 对同一张表中EmployeeId 的引用

目标: 每当使用EmployeeIdTeamleaderIdCompanyId 在表中插入一行时,使用AFTER INSERT 触发器自动填充TopTeamleaderIdLEVELParentTree

代码:

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 

问题: 假设一家公司有 1000000 名员工,这个查询需要很长时间才能执行。如何优化它以便只考虑插入行的父母?

【问题讨论】:

  • 您的业务规则是什么?请解释并举例说明。
  • 看到规则不清楚,也不清楚您的表格设计的目的。下面的脚本是可以的,但即使从递归 CTE 的角度来看,您的脚本上面也肯定是错误的。它也可以优化。

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


【解决方案1】:

递归 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

退货

【讨论】:

  • 我仍在寻找答案,但乍一看生成的ParentTree 与我想要的相反。例如,EmployeeId = 16 在您的示例中,ParentTree 应该是 16&gt;1
  • @ShyamalParikh 更正了 ParentTree 的序列
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
相关资源
最近更新 更多