【问题标题】:SQL Server Stored Procedure - 'IF statement' vs 'Where criteria'SQL Server 存储过程 - “IF 语句”与“Where 条件”
【发布时间】:2010-12-21 00:23:11
【问题描述】:

在我脑海中沸腾了很久的问题,以下两个存储过程中哪一个会执行得更好。

过程 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

过程 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

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

如果使用 @IncludeDepartmentInfo 的交替值调用 proc 1/proc 2,那么据我了解,proc 2 会执行得更好,因为无论@IncludeDepartmentInfo 的值如何,它都会保留相同的查询计划,而 proc1 将更改查询计划每次通话

答案真的很重要

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

【问题讨论】:

    标签: sql-server tsql query-optimization


    【解决方案1】:
    SELECT Departments.* FROM Departments, Employees
        WHERE Departments.DepartmentId = Employees.DepartmentId 
        AND Employees.EmployeeId = @EmployeeId 
        AND @IncludeDepartmentInfo = 1
    

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

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

    【讨论】:

      【解决方案2】:

      从一致性的角度来看,数字 2 将始终返回 2 个数据集。抛开重载不谈,您不会有一个可能返回结果的客户端代码方法,也可能没有。

      如果您重用此代码,其他调用客户端也必须知道此标志。

      如果代码做了 2 个不同的事情,那为什么不做 2 个不同的存储过程呢?

      最后,使用现代 JOIN 语法并将连接与过滤分开是更好的做法。在这种情况下,personall我也会使用 EXISTS。

      SELECT
          D.*
      FROM
          Departments D
          JOIN
          Employees E ON D.DepartmentId = E.DepartmentId
      WHERE  
          E.EmployeeId = @EmployeeId 
          AND
          @IncludeDepartmentInfo = 1
      

      【讨论】:

      • 我知道我们可以使用两个存储过程,并且有一个优雅的 join 语句(用 join 替换老式查询),但我的简单问题是两个中哪个性能更好?
      • @scorpio:这取决于:小桌子还是宽桌子?大的还是小的结果?计划不确定性的开销将超过不发送少量数据的任何优势。
      • OFF 主题:使用两个存储过程最好是使用两个表函数。
      • gbn 感谢您的回复。从客户端代码中也可以看到,我认为 proc 2 将一致地返回两个结果集,这取决于第二个结果集是否为空。并在包含超过 100k 记录的表并再次返回 1000 条记录时采用这种情况,哪个 proc 会更好?我有一个实际场景,其中数据库表有大量超过 10 列的记录,我只是通过尝试给出一个简单的例子来问这个问题。
      • @scorpio:我有 2 个存储过程。根据 Remus,如果在 WHERE 中,仍然可以评估第二个查询。 IF 更改签名
      【解决方案3】:

      性能差异太小,任何人都不会注意到。

      Premature optimization is the root of all evil. 不再担心性能,开始实施让您的客户微笑的功能。

      【讨论】:

      • 我明白你在说什么,但似乎这句话可以作为借口,类似于“我的代码是自记录的,所以我不需要创建文档”。
      • :) 聪明并不意味着你不能问基本问题,没有冒犯
      • 我同意过早的选择是万恶之源,但这并不意味着我们不应该从一开始就写得更好。有些系统认为这种微小的性能改进很重要。
      【解决方案4】:

      当您使用“if”语句时,您可能只运行一个查询而不是两个。我认为一个查询几乎总是比两个快。如果第一个查询很复杂并且运行时间很长,而第二个查询很简单,那么您关于查询计划的观点可能是有效的。但是,第一个查询看起来像是基于主键检索单行 - 每次可能都非常快。所以,我会保留“如果”——但我会通过测试来验证。

      【讨论】:

      • 本质上,第一个查询可能会返回当前示例中没有的多条记录,第二个查询在 proc 2 中也是一种可选的,其中 SQL 查询优化器本身将首先匹配常量标准并且不会如果不匹配,则匹配更多条件。同样,这些只是我对 SQL 查询优化器的假设
      • 真正了解的唯一方法是针对您的真实实时数据进行测试,看看会发生什么。 Andomar 的观点很好 - 在大多数情况下,差异太小而无需担心。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-17
      • 2015-11-21
      • 2014-01-24
      • 1970-01-01
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多