目前,我在我们的应用程序中找到了一个查询,其执行计划是“索引扫描”。嗯,这里有一些背景知识:
以下是我们的查询:
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索引上的“索引扫描”......出了什么问题?
如果我使用相同的查询但不使用“sp_executesql”,如:
select b,a from table where b in(94,161,4,50,166,52,53,90,100,123)
按预期显示“聚集索引搜索”
为什么SQL Server会对第一个查询使用“索引扫描”?它与功能有关吗? “sp_executesql”本身?
谢谢你 万斯
答案 0 :(得分:1)
我已经看过我自己的数据库中类似查询的执行计划,可以看到差异,但我无法完全解释它;我只是觉得我的发现可能有用。
差异似乎是由于在编译的查询中使用了参数。
在下面的示例中,我使用的是来自我所拥有的数据库的[Resource]表,您必须更改查询的名称。
正如您发现在管理工作室中直接执行查询会导致索引搜索
使用带参数的版本进行扫描
如果您完全准备好语句,然后将其传递给数据库,例如
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在他的回答中所说)。
我在本文中找到了相同的信息:Dynamic Search Conditions in T-SQL
编辑2:回应Martin的评论,这是他的SQL语句的执行计划
答案 1 :(得分:1)
差异可能是由于在不同数据或不同参数意味着表扫描/索引搜索适当时执行的缓存查询计划。 (SQL命令文本本身不同,因此它们在计划缓存中都有不同的条目)。如果要对此进行测试,可以使用以下命令清除计划缓存:
DBCC FREEPROCCACHE -- Don't run me on a production SQL server!
然后尝试再次运行这两个命令,看看是否还有差异(如果您愿意挖掘计划缓存,上述命令的版本可以安全生产)
请注意,表扫描并不总是坏事 - 尤其是当表格很窄并且行数不多时(在您的示例中看起来就是这种情况)。在这种情况下,表扫描可以比索引搜索更有效。