【问题标题】:Sql Excution Plan Shows Different result for same inputsSql 执行计划显示相同输入的不同结果
【发布时间】:2010-07-12 12:04:55
【问题描述】:
declare @name varchar(156)
set @name ='sara'
--Query 1:
SELECT [PNAME] FROM [tbltest] where [PNAME] like '%'+@name+'%'
--Query 2:
SELECT [PNAME] FROM [tbltest] where [PNAME] like '%sara%'
假设 [tbltest] 的 [PNAME] 列上有一个 NoneClustered Index。
运行查询时,执行计划显示查询 1 的索引搜索和查询 2 的索引扫描。
我希望 Excution Paln 对两个查询都显示索引扫描,但由于在第一个查询中使用了参数,它显示索引搜索。
那我到底是什么东西?
在这两个查询中,我们在另一端都使用了“%”,并且知道在这种状态下,sql 不考虑索引
但是为什么在第一个查询执行计划中显示索引搜索?
谢谢
【问题讨论】:
标签:
sql
database
sql-server-2005
【解决方案1】:
查询一使用参数,查询二使用常量。
如果更改常量值,查询 2 的计划将不会被重用。
plan 1 的查询可以。在这种情况下,SQL Server(简单地)保留它的选项以重用计划。
又名:查询不相同。
如果你force parameterisation,那么你应该让两个查询都像查询1一样运行。但我没有尝试过......
【解决方案2】:
如果您对表和正在使用的索引执行 DBCC SHOW_STATISTICS,请在输出的第一行中查找“String Index = YES”。 SQL Server 维护了一些额外的统计信息来满足诸如“%x”之类的查询
在第一个查询中,您可能会看到计算出的标量值 - 查看 LikeRangeStart('%'+@name+'%') 的查询计划。索引查找针对的是这些值,而不是针对 %sara% 的索引扫描。
我不知道这是如何工作的。为什么 SQL Server 不够聪明,无法将 'sara' 转换为常量并以我也不知道的相同方式进行查询。但我认为这就是正在发生的事情。
它对 %sara% 进行索引扫描,读取整个索引。针对 %+@name+% 它创建 RangeStart/RangeEnd/RangeInfo 计算值,并使用它们以某种方式利用附加字符串统计信息进行索引搜索。
【解决方案3】:
我认为迈克在你是否达到索引的问题上是正确的。您对成本的跟进可能需要更多地了解您的数据在表中的分布方式。我已经看到由于需要两次磁盘读取而命中索引的成本更高的情况。要了解原因,您必须知道数据在索引中的分布方式、页面可容纳多少记录以及缓存方案是什么。
我会说调整带有前导 % 的查询可能很困难。数据库将需要完全遍历您的索引(或表)并点击每个节点以查找包含“sara”的值。根据您的需要,您可能需要考虑全文搜索(即,是否使用此查询中的参数值,因为它是作为应用程序用户的输入提供的)。