sp_execute 选择不同的查询计划

Posted

技术标签:

【中文标题】sp_execute 选择不同的查询计划【英文标题】:sp_execute chooses different query plan 【发布时间】:2016-08-23 08:35:33 【问题描述】:

所以这就是场景:

表格有很多字段。 Field2 是聚集索引中的唯一字段。 存在Field1、Field2唯一索引,不包含任何其他字段。

表有 500000 行,其中 499900 为 Field1 有空值。

查询 1:

SELECT TOP (1) * 
FROM Table WITH(UPDLOCK) 
WHERE (Field1='XXX') ORDER BY Field1 DESC, Field2 DESC OPTION(OPTIMIZE FOR UNKNOWN)

产生Index Seek到唯一索引Field1,Field2,然后key查找到聚集索引,速度非常快。

然而,

Declare @P1 int;  
Exec sp_prepare @P1 output,   
N'@0 nvarchar(20)',  
N'SELECT TOP (1) * 
FROM Table WITH(UPDLOCK) 
WHERE (Field1=@0) ORDER BY Field1 DESC, Field2 DESC OPTION(OPTIMIZE FOR UNKNOWN)';  
Exec sp_execute @P1, N'XXX'
EXEC sp_unprepare @P1;  

产生聚集索引扫描,速度很慢。

DBCC FREEPROCCACHE 没有帮助,所以这不是现金查询计划的问题。

问题是,为什么会有差异?

谢谢。

已编辑:不小心将相同的内容放入第二个查询中,已更新以正确反映它。

【问题讨论】:

我想知道如果@P1 参数被硬编码到命令字符串中会发生什么。那么执行时间是多少呢? 硬编码参数使计划相同。 【参考方案1】:

这是由于参数是可变的,如果你硬编码它会返回相同的计划,或者如果你将参数放入正常执行中,它会生成要扫描的计划。

【讨论】:

显然这是唯一的区别,但为什么呢?这是在哪里记录的? 您可以在this 文章中获得一些信息。在我看来,Itzik Ben-Gan 的一本书“查询 Microsoft SQL Server 2012”第 17 章第 2 课:“使用参数化查询和批处理操作”对此进行了很好的解释。 您认为文章的哪一部分与此有关?

以上是关于sp_execute 选择不同的查询计划的主要内容,如果未能解决你的问题,请参考以下文章

为啥插入和选择查询的结果集不同

如何让 MS-Access 为我的查询选择不同/正确的执行计划

跟我一起读postgresql源码——Executor(查询执行模块之——可优化语句的执行)

请解释sql server选择的查询计划

实体框架缓存的查询计划性能随参数不同而降低

执行计划中的“查询成本”如何工作?