我有三个表'Employees','Departments'和'EmployeesInDepartments' 'Employees'表引用'Departments'表(每个员工必须有一个DepartmentId)。但是,通过向“EmployeeInDepartments”表添加条目(EmployeeId和DepartmentId),员工可以存在于多个部门中。
我目前有以下存储过程来通过departmentId检索员工:
CREATE PROCEDURE dbo.CollectEmployeesByDepartmentId
(
@DepartmentId int,
@IsDeleted bit
)
AS
BEGIN
SELECT Employees.*
FROM Employees
WHERE ((Employees.IsDeleted = @IsDeleted )
AND ((Employees.DepartmentId = @DepartmentId)
OR (Employees.EmployeeId IN (SELECT EmployeesInDepartments.EmployeeId
FROM EmployeesInDepartments
WHERE (EmployeesInDepartments.DepartmentId = @DepartmentId)
)
)
)
)
END
如何优化此存储过程并可能使用JOINS?
答案 0 :(得分:4)
我的第一个建议是从员工表中删除部门ID。将所有记录插入Departments表中的员工。
然后这是一个简单的内部联接。
当然,永远不要在生产代码中使用select *。
答案 1 :(得分:4)
以下是我对您的查询的重写:
WITH summary AS (
SELECT e.*
FROM EMPLOYEES e
WHERE e.isdeleted = @IsDeleted
AND e.parentid = 0)
SELECT a.*
FROM summary a
WHERE a.departmentid = @DepartmentId
UNION
SELECT b.*
FROM summary b
JOIN EMPLOYEESINDEPARTMENTS ed ON ed.employeeid = b.employeeid
AND ed.departmentid = @DepartmentId
UNION必须删除重复项 - 如果您知道永远不会重复,请将UNION
更改为UNION ALL
。
被称为“摘要”的CTE没有提供任何性能优势,只是简写。
答案 2 :(得分:1)
SELECT E.*
FROM Employees E
Left Join EmployeesInDepartments EID ON E.EmployeeId = EID.EmployeeId
And E.DepartmentId <> @DepartmentId
WHERE E.IsDeleted = @IsDeleted
And
(
E.DepartmentId = @DepartmentId
Or (EID.DepartmentId = @DepartmentId)
)
编辑以包含IsDeleted逻辑。 我同意其他一些答案,你的设计应该改变。但是这个查询应该这样做。如果您在EmployeesInDepartments中有重复项,则可以将其更改为Select Distinct。
答案 3 :(得分:0)
我建议您将查询中使用的IN
子句更改为WHERE EXISTS
。
如果在查询中使用IN
,则意味着您没有利用表中定义的索引,查询将执行影响查询性能的完整表扫描。
您可以查看此帖子以将IN
转换为WHERE EXISTS
: