提高递归 CTE 计算总计的性能

问题描述 投票:0回答:2

我有一个 SQL Server 数据库,其中的 Employee 表包含以下结构:

CREATE TABLE Employee (
EmployeeID INT PRIMARY KEY,
ManagerID INT,
EmployeeName NVARCHAR(50),
Salary DECIMAL(18, 2));

我使用递归通用表表达式(CTE)来计算每个员工及其下属的总工资。但是,当员工数量较多时,查询性能会变得很慢。

WITH RecursiveSalaryCTE AS (
SELECT EmployeeID, ManagerID, EmployeeName, Salary
FROM Employee
WHERE ManagerID IS NULL

UNION ALL

SELECT e.EmployeeID, e.ManagerID, e.EmployeeName, e.Salary
FROM Employee e
JOIN RecursiveSalaryCTE r ON e.ManagerID = r.EmployeeID)

    SELECT EmployeeID, EmployeeName, Salary,
           (SELECT SUM(Salary) FROM RecursiveSalaryCTE WHERE ManagerID = e.EmployeeID) AS TotalSubordinateSalaries
    FROM RecursiveSalaryCTE e;

有没有更好的方法来优化这个查询?任何可以提供更快结果的替代方法或对查询的修改将不胜感激。

员工表的示例数据:

    INSERT INTO Employee (EmployeeID, ManagerID, EmployeeName, Salary)
    VALUES
    (1, NULL, 'John', 10000.00),
    (2, 1, 'Alice', 7500.00),
    (3, 1, 'Bob', 8000.00),
    -- ... more data ...
    (1000, 999, 'Eve', 6000.00);
sql tsql common-table-expression
2个回答
0
投票

这个怎么样... https://dbfiddle.uk/NwF09y4y

--manager list
with managers as
  (
  select distinct ManagerID
from Employee
  )
--sum sub salaries  
,TotalSubordinateSalaries as
  (
select ManagerID, sum(Salary) TotalSubordinateSalaries
from Employee
group by ManagerID
  )
  
select EmployeeID, EmployeeName, Salary ,ts.TotalSubordinateSalaries
  from Employee e
--identify the manager
left join managers m on m.ManagerID=e.EmployeeID
--join their subs
left join TotalSubordinateSalaries ts on ts.ManagerID = m.ManagerID

0
投票
with RecursiveSalaryCTE(EmployeeID, managerid, salary, path) as (
    SELECT EmployeeID, managerid, Salary, '/' || EmployeeID
    FROM employee
    WHERE managerid IS NULL
    
    UNION ALL
    
    SELECT e.EmployeeID, e.managerid, e.salary, r.path || '/' || e.EmployeeID 
    FROM employee e
    JOIN RecursiveSalaryCTE r ON e.managerid = r.EmployeeID

)
select EmployeeID, managerid, salary, Total_all_sub, 
    sum(salary) over(partition by managerid) as total_same_manager
from (
    select r.EmployeeID, r.managerid, r.salary,
        SUM(r1.Salary) Total_all_sub
    from RecursiveSalaryCTE r
    join RecursiveSalaryCTE r1 on substring(r1.path,1,length(r.path)) = r.path 
    group by r.EmployeeID, r.managerid, r.salary
)
;

EID MID SAL TREE LVL
1       100 345 100
2   1   90  160 175
3   1   85  85  175
4   2   70  70  70
© www.soinside.com 2019 - 2024. All rights reserved.