【问题标题】:Parameterized SQL and NULL running slow参数化 SQL 和 NULL 运行缓慢
【发布时间】:2011-03-29 04:52:13
【问题描述】:

我正在从 .net 调用一些参数化的 sql。我不知道为什么,但是在检查参数是否为 NULL 时,与不包含参数时相比,sql 运行速度很慢:

所以这个:

exec sp_executesql N'
 SELECT [id]
 FROM [tblAddress] (nolock)
 WHERE 1 = 1
 AND ([id] = @id OR @id  IS NULL)

',N'@id int',
@id=4395

比这个运行得更快:

exec sp_executesql N'
 SELECT [id]
 FROM [tblAddress] (nolock)
 WHERE 1 = 1
 AND ([id] = @id)

',N'@id int',
@id=4395

运行 SQL 分析器,超过 100 万行的顶部查询的持续时间为 175 次,读取次数为 3720,但第二个查询的持续时间为 1 次,并且只有 3 次读取。

为什么会有这样的差异以及如何改进?

【问题讨论】:

    标签: sql sql-server tsql sql-server-profiler


    【解决方案1】:

    OR 子句不是 SARGABLE,因此使用的计划是扫描,而不是像第二个那样的搜索

    试试这个:2 次搜索

    SELECT [id]
     FROM [tblAddress]
     WHERE [id] = @id
    UNION ALL
    SELECT [id]
     FROM [tblAddress] 
     WHERE @id IS NULL)
    

    注意:您不需要 NOLOCK 提示。或1=1

    【讨论】:

    • 这样更快,谢谢。我不明白为什么它会在@id IS NULL 语句不需要表的情况下进行扫描?
    • 还有1=1 是如何加快速度的?无论正在评估什么,它是否总是在使用 OR 语句时进行扫描?
    • 1=1 仅适用于 dnycmic SQL,所以我假设您想要它。它不是必需的。 @ID 仍然是一个参数,因此当它不为 NULL 时需要包含在计划中。但是你为什么还要使用 sp_executesql...?
    • @g.foley:附带说明:ADO.NET 不一定使用 sp_executeSql - 它可能看起来就像在 SQL Profiler 中一样(相反,它可能使用 TDS protocl 的特殊 RPC 调用)。更多信息:weblogs.sqlteam.com/dang/archive/2008/02/18/…
    【解决方案2】:

    如果@id 为 NULL,则无法进行 SEEK,因此它将始终 SCAN,并且总是很慢(取决于 [tblAddress] 中的行数。为了解决这个问题,您可能想要通过指定 TOP(N) 子句来限制查询返回的结果数量。

    所以我会做的是:

    IF @id IS NOT NULL
    BEGIN
        SELECT [id]
          FROM [tblAddress]
         WHERE [id] = @id
    END
    ELSE
    BEGIN
        SELECT TOP(20) [id] FROM [tblAddress] 
    END
    

    另外,如果没有严格要求,我不会使用 NOLOCK 提示。

    【讨论】:

      猜你喜欢
      • 2019-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 2015-12-29
      • 2017-09-24
      • 2011-09-01
      相关资源
      最近更新 更多