SQL Server查询:快速使用文字但速度慢而变量

Gav*_*vin 40 sql-server performance sql-server-2008

我有一个视图,使用CTE从表中返回2个整数.如果我查询这样的视图,它会在不到一秒的时间内运行

SELECT * FROM view1 WHERE ID = 1
Run Code Online (Sandbox Code Playgroud)

但是,如果我像这样查询视图需要4秒钟.

DECLARE @id INT = 1
SELECT * FROM View1 WHERE ID = @id
Run Code Online (Sandbox Code Playgroud)

我检查了2个查询计划,第一个查询正在主表上执行Clustered index seek返回1个记录,然后将其余的视图查询应用于该结果集,其中第二个查询正在执行索引扫描,即返回大约3000条记录而不仅仅是我感兴趣的记录,然后过滤结果集.

有没有明显的东西我试图让第二个查询使用Index Seek而不是索引扫描.我正在使用SQL 2008,但我所做的任何事情都需要在SQL 2005上运行.起初我认为这是某种参数嗅探问题,但即使清除缓存,我也会得到相同的结果.

eri*_*len 42

可能是因为在参数的情况下,优化器无法知道该值不为null,因此需要创建一个计划,即使它返回正确的结果.如果您有SQL Server 2008 SP1,则可以尝试添加OPTION(RECOMPILE)到查询中.

  • @pst - 这是正确的建议解决方案,但错误的推理.OP具有变量而不是参数.问题是选择性估计,因为SQL Server不进行变量嗅探.不是"创建一个处理'NULL'的计划" (4认同)
  • +1在这里像冠军一样工作(并且比试图强制各种连接/计划等手动更少) (2认同)

Dam*_*ver 5

您可以在查询中添加OPTIMIZE FOR 提示,例如

DECLARE @id INT = 1
SELECT * FROM View1 WHERE ID = @id OPTION (OPTIMIZE FOR (@ID = 1))
Run Code Online (Sandbox Code Playgroud)


Mor*_*bia 5

在我的例子中,数据库表列类型被定义为 VarChar,参数化查询参数类型被定义为 NVarChar,这CONVERT_IMPLICIT在实际执行计划中引入以在比较之前匹配数据类型,这是母猪性能的罪魁祸首,2 秒 vs 11 秒。只需更正参数类型即可使参数化查询与非参数化版本一样快。

一种可能的方法是使用CAST参数,如下所示:

SELECT ...
FROM ...
WHERE name = CAST(:name AS varchar)
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助有类似问题的人。