2011-03-01 69 views
2

目前,我发现在我们的应用程序一个查询及其执行计划“索引扫描”。好了,这里有一些背景:SQL Server 2005中执行计划的问题

  1. 它有三个列,类型为“idType :bigint“
  2. 手头上只有200件爆炸物品
  3. 有列(a:PK,b:FK,c:FK),我们有两个索引(一个聚簇索引(b,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)', 
    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”本身有关?

谢谢你在进阶 万斯

+1

实际“CREATE TABLE”和“CREATE INDEX”语句比描述更容易理解(一般说明:只要删除多余的列,如果表格很宽,并且问题可以用列的子集来演示) – 2011-03-01 09:16:27

+0

尝试在存储过程中执行代码,查看执行计划是否与sp_execute或T-SQL计划相同将会很有趣。 (这不一定是解决您的问题,我只是想获得更多信息) – Tony 2011-03-01 09:53:37

+0

谢谢大家的回复! @Tony我把第一个查询'exec sp_executesql N'...)在一个SP中,并得到“index_scan”相同。这个问题涉及到我的测试表的值是小的吗?我只有200个项目,所以sql服务器不会“优化”它的查询执行吗? – Vance 2011-03-01 10:03:08

回答

1

我不得不看看类似的查询在我自己的数据库的执行计划,可以看到有差别,但我不能完全解释它;我只是认为我的发现可能有用。

的差异似乎是由于在编译的查询参数的使用。

在下面的例子中我使用的是从一个数据库中,我有一个名为[资源]表中,你将不得不更改名称为您查询。

正如你已经发现直接在管理工作室结果执行查询在索引查找

T_SQL Query

使用版本参数给出了一个扫描

enter image description here

如果完全准备好声明,然后将其传递给数据库,例如

exec('select id from [Resource] where id in (1,5,7,9,10)') 

你会得到一个索引查找再次

enter image description here

有趣的是看缓存计划

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:针对马丁的评论,这里是他的SQL语句的执行计划

enter image description here

+0

我想它归结为选择性。如果你从这里得到5个id,选择top(5)id,从[Resource]组中按COUNT(*)desc'选择COUNT(*),然后尝试将它们作为文字来扫描还是查找? – 2011-03-01 12:33:36

+0

@Martin:我发布了这个查询,但我想我误解了你试图达到的目标。 – Tony 2011-03-01 12:47:48

+0

是的,你有!假设你的查询显示5个最常见的id是'100,101,102,103,104'我想知道你会从[Resource]中得到什么样的计划,其中id为(100,101,102,103,104)'如果这仍然给你一个寻找计划然后我可以对于参数化版本进行扫描根本没有理由,因为这应该是最糟糕的情况。 – 2011-03-01 13:03:55

1

的差异可能这是由于在不同的数据或不同的参数意味着表扫描/索引搜索合适时执行的缓存查询计划。 (SQL命令文本本身不同,因此它们在计划缓存中都有不同的条目)。如果你想测试这一点,你可以使用此命令清除计划缓存:

DBCC FREEPROCCACHE -- Don't run me on a production SQL server! 

然后尝试再次运行这两个命令,看看是否有还是有区别的(也有说是生产安全的,如果上面的命令版本你愿意通过计划缓存挖掘)

请注意,表扫描并不总是一件坏事 - 特别是当表狭窄,并没有多少行(这看起来是在你的情况下例)。在这种情况下,表扫描可能比索引查找有效得多。