SQL参数减慢查询速度

时间:2011-10-24 10:14:58

标签: sql sql-server sql-server-2008 ado.net parameterized

我有一个查询,我通过ADO.NET与SQL Server 2008R2一起使用。当我在内联使用LIKE子句时,它在不到一秒的时间内工作,从200万返回5行。如果我在SSMS查询开始时像在.NET中那样声明参数,那就需要永远。

这是相同的查询,但已参数化。

第一个(工作正常)是(工作正常):

;WITH Results_CTE AS (
    SELECT  ld.* , ROW_NUMBER() OVER (ORDER BY PK_ID) AS RowNum  
    FROM list..List_Data ld 
    WHERE Name IS NOT NULL  AND 
    Postcode LIKE 'SW14 1xx%' 
) SELECT * FROM Results_CTE 

永远的第二个是:

declare @postcode varchar(10) = 'SW14 1xx'
;WITH Results_CTE AS (
    SELECT  ld.* , ROW_NUMBER() OVER (ORDER BY PK_ID) AS RowNum  
    FROM list..List_Data ld
    WHERE Name IS NOT NULL  AND 
    Postcode LIKE @postcode +'%' 
) SELECT * FROM Results_CTE 

我认为这与SQL Server的内部工作有关,但我真的不知道。

4 个答案:

答案 0 :(得分:2)

使用

SELECT * 
FROM Results_CTE 
OPTION (RECOMPILE)

SQL Server不会嗅探变量的值,因此它不知道它将具有多大的选择性,并且可能会假设查询将返回比实际情况更多的行,并为您提供针对此优化的计划。

在你的情况下,我很确定在好的计划中你会发现它使用非覆盖的非聚集索引来评估PostCode谓词和一些查找来检索丢失的列,而在错误的计划中(因为它猜测查询将返回更多的行),它避免了这一点,支持全表扫描。

答案 1 :(得分:2)

您可以使用optimize for让参数化查询使用与具有特定参数的查询相同的执行计划:

SELECT * 
FROM Results_CTE 
OPTION (OPTIMIZE FOR (@postcode = 'SW14 1xx'))

答案 2 :(得分:2)

我在谷歌上搜索C#中SqlCommand.Parameters.Add()的潜在问题,我找到了这个页面。我知道这是一个SQL Server帖子,但其他人可能会通过谷歌找到它,它可能会帮助他们使用C#。

对我来说,上述答案都没有,所以我尝试了另一种方法。

而不是:

cmd.Parameters.Add(new SqlParameter("@postcode", postcode));

我改为使用了这个:

// Replace SqlDbType enumeration with whatever SQL Data Type you're using.
cmd.Parameters.Add("@postcode", SqlDbType.VarChar).Value = postcode;

不要忘记命名空间:

using System.Data;

希望这有助于某人!

答案 3 :(得分:1)

这看起来像是由参数嗅探引起的问题 - 在计划编译期间,SQL Server“嗅探”当前参数值并使用它来优化查询。这可能导致的最常见问题是,如果查询在第一次运行/编译时使用“奇数”参数值运行,在这种情况下查询计划将针对该参数值进行优化,参数嗅探可能会导致所有其他问题

在您的情况下,如果使用@postcode的空/空值运行查询,则查询使用LIKE '%'子句,这很可能导致表扫描为{{1在过滤器的开头使用了通配符。看起来计划最初使用空LIKE参数运行/编译,或者SQL Server以某种方式被此参数搞糊涂。

您可以尝试以下几种方法:

  1. 标记查询以进行重新编译,然后使用@postcode的非空值再次运行查询。
  2. “屏蔽”参数以尝试阻止参数嗅探,
  3. 例如:

    @postcode

    虽然这个查询看起来应该表现得与我发现SQL Server以奇怪方式处理参数的方式完全一样 - 关于何时使用参数嗅探的规则可能有点奇怪,所以你可能想要玩弄上面的变化。