Sql server SQL Server 2005执行计划问题
目前,我在我们的应用程序中发现了一个查询,它的执行计划是索引扫描。下面是一些背景: 它有三列,类型为idType:bigint 手头只有200件物品 这里有一列a:PK,b:FK,c:FK,我们有两个索引,一个聚集索引x,c,一个PK非聚集索引a 以下是我们的疑问:Sql server SQL Server 2005执行计划问题,sql-server,sql-execution-plan,Sql Server,Sql Execution Plan,目前,我在我们的应用程序中发现了一个查询,它的执行计划是索引扫描。下面是一些背景: 它有三列,类型为idType:bigint 手头只有200件物品 这里有一列a:PK,b:FK,c:FK,我们有两个索引,一个聚集索引x,c,一个PK非聚集索引a 以下是我们的疑问: exec sp_executesql N'select b,a from table where b in (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9)',
exec sp_executesql N'select b,a from table where b in (@P0, @P1, @P2,
@P3, @P4, @P5, @P6, @P7, @P8, @P9)',
N'@P0 bigint, @P1 bigint, @P2 bigint, @P3 bigint, @P4 bigint, @P5 bigint,
@P6 bigint, @P7 bigint, @P8 bigint, @P9 bigint',
94, 161, 4, 50, 166, 52, 53, 90, 100, 123
它从执行计划中显示为pk index上的索引扫描…出了什么问题
如果我使用相同的查询,但不使用sp_executesql,如:
select b,a from table where b in(94,161,4,50,166,52,53,90,100,123)
它显示了我所期望的聚集索引搜索
为什么SQL Server会对第一个查询使用索引扫描?它与功能有关吗
sp_executesql本身
谢谢你的支持
Vance我在自己的数据库中查看了类似查询的执行计划,可以看到不同之处,但我无法完全解释;我只是觉得我的发现可能有用 这种差异似乎是由于在已编译的查询中使用了参数 在下面的示例中,我使用的是一个数据库中名为[Resource]的表,您必须更改查询的名称 正如您所发现的,在ManagementStudio中直接执行查询会导致索引搜索 使用带有参数的版本进行扫描 如果您完全准备好语句,然后将其传递给数据库,例如
exec('select id from [Resource] where id in (1,5,7,9,10)')
您再次获得索引搜索
有趣的是查看缓存的计划
SELECT cp.objtype,cp.usecounts,q.TEXT
FROM sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_query_plan(cp.plan_handle) p
cross apply sys.dm_exec_sql_text(cp.plan_handle) AS q
WHERE cp.cacheobjtype = 'Compiled Plan'
对于我执行的三条语句
objtype usecounts text
------- --------- ----
Adhoc 1 select id from [Resource] where id in (1,5,7,9,10)
Prepared 1 (@p1 int, @p2 int, @p3 int, @p4 int, @p5 int)select id from [Resource] where id in (@p1, @p2, @p3, @p4, @p5)
Adhoc 1 select id from [Resource] where id in (1,5,7,9,10)
正如您所看到的,SQL是完全不同的。不幸的是,这就是我所能解释的索引选择的不同之处。也许其他人可以更进一步
编辑1:我读了更多的内容,归结到乐观主义者必须制定一个计划来满足所有可能的参数值,正如Kragen在他的回答中所说的
我在本文中发现了相同的信息:
编辑2:作为对Martin评论的回应,下面是他的SQL语句的执行计划
这种差异可能是由于在不同数据或不同参数意味着表扫描/索引查找是合适的时候执行了缓存查询计划。SQL命令文本本身是不同的,因此它们在计划缓存中都有不同的条目。如果要对此进行测试,可以使用以下命令清除计划缓存:
DBCC FREEPROCCACHE -- Don't run me on a production SQL server!
然后再次尝试运行这两个命令,看看是否仍然存在差异。如果您愿意挖掘计划缓存,则上述命令的某些版本是生产安全的
请注意,表扫描并不总是一件坏事,尤其是当表很窄并且没有太多行时,在您的示例中,情况就是这样。在这种情况下,表扫描可能比索引查找更有效。实际的CREATE table和CREATE index语句比描述更容易理解。一般警告:如果删除了无关的列,如果表很宽,这个问题可以用columnsTry的一个子集在存储过程中执行代码来演示,看看执行计划是否与sp_execute或T-SQL计划相同会很有趣。这不一定能解决你的问题,我只是想得到更多的信息谢谢大家的回复@Tony我把第一个查询“exec sp_executesql N”。。。在SP中,并获得相同的索引扫描。这个问题是否与我的测试表值小有关?我只有大约200个条目,所以sql server不会优化它的查询执行吗?我想这可以归结为选择性。如果你从这里获得5个id,那么从[Resource]中选择top 5 id,COUNT*按id分组,order by COUNT*desc,并将它们作为文本进行尝试。你得到扫描还是搜索?@Martin:我发布了查询,但我想我误解了你试图实现的目标。是的,你得到了!假设您的查询显示5个最常见的id是100101102103104,我想知道您将从[Resource]中获得选择id的什么计划如果100101102103104中的id仍然为您提供了一个带有搜索的计划,那么我想不出任何理由支持参数化版本进行扫描,因为这应该是最坏的情况。@Martin-好的,我明白您的意思了。我确实尝试过从[Resource]中选择id,其中id在1,5,7,9,10中看到了执行寻道的第一个执行计划图像。我正在使用一些数据来测试查询,它与VanceZhao的数据不同。实际上,我们使用ibatis,上面的带有参数的查询就是从中生成的。是的,“从[Resource]中选择id,其中id在1,5,7,9,10中”将执行搜索,并且在“从[Resource]中选择id,其中id”下获取搜索in@a,@a,@a'但在查询时真正得到扫描'从[Resource]中选择id,其中idin@a,@b,@c