SQL Server 存储过程 - “IF 语句”与“Where 条件”

sco*_*pio 6 t-sql sql-server query-optimization

这个问题在我脑子里沸腾了很久,从下面两个存储过程中哪个会表现得更好。

过程 1

CREATE PROCEDURE GetEmployeeDetails @EmployeeId uniqueidentifier,
@IncludeDepartmentInfo bit

AS
BEGIN

    SELECT * FROM Employees 
    WHERE Employees.EmployeeId = @EmployeeId

    IF (@IncludeDepartmentInfo = 1)
    BEGIN
        SELECT Departments.* FROM Departments, Employees
        WHERE Departments.DepartmentId = Employees.DepartmentId 
        AND Employees.EmployeeId = @EmployeeId
    END
END
Run Code Online (Sandbox Code Playgroud)

过程 2

CREATE PROCEDURE GetEmployeeDetails @EmployeeId uniqueidentifier,
 @IncludeDepartmentInfo bit
AS
BEGIN

    SELECT * FROM Employees 
    WHERE Employees.EmployeeId = @EmployeeId

    SELECT Departments.* FROM Departments, Employees
    WHERE Departments.DepartmentId = Employees.DepartmentId 
    AND Employees.EmployeeId = @EmployeeId 
    AND @IncludeDepartmentInfo = 1

END
Run Code Online (Sandbox Code Playgroud)

两者之间的唯一区别是使用“if 语句”。

如果使用@IncludeDepartmentInfo 的交替值调用 proc 1/proc 2,那么根据我的理解,proc 2 的性能会更好,因为无论 @IncludeDepartmentInfo 的值如何,它都会保留相同的查询计划,而 proc1 将在每次调用中更改查询计划

答案真的很有趣

PS:这只是一个场景,请不要看显式的查询结果,而是看例子的本质。我真的很关注查询优化器的结果(在“if 和 where”的两种情况下以及它们的差异),我知道有很多方面可能会影响我想在这个问题中避免的性能。

Rem*_*anu 2

SELECT Departments.* FROM Departments, Employees
    WHERE Departments.DepartmentId = Employees.DepartmentId 
    AND Employees.EmployeeId = @EmployeeId 
    AND @IncludeDepartmentInfo = 1
Run Code Online (Sandbox Code Playgroud)

当 SQL 编译这样的查询时,必须针对@IncludeDepartmentInfo 的任何值进行编译。结果计划很可能是扫描表并执行连接以及之后的计划检查变量,从而导致不必要的 I/O。优化器可能很聪明,会将变量检查移到执行计划中的实际 I/O 操作之前,但这永远无法保证。这就是为什么我总是建议在 T-SQL 中对需要根据变量值执行非常不同的查询(典型的示例是 OR 条件)使用显式 IF。

gbn 的观察也很重要:从 API 设计的角度来看,最好具有一致的返回类型(即始终返回相同形状和数量的结果集)。