5

今天,我偶然发现了一个有趣的性能问题,即在 Sql Server 2005 SP2 上运行的存储过程在兼容级别为 80 (SQL2000) 的数据库中运行。

proc 运行大约 8 分钟,执行计划显示使用了一个实际行数为 1.339.241.423 的索引,这比表本身的“真实”实际行数 1.144.640 高大约 1000 倍,如正确显示通过估计的行数。所以查询计划优化器给出的实际行数肯定是错误的!

替代文字

有趣的是,当我将 proc 中的 procs 参数值复制到局部变量并在实际查询中使用局部变量时,一切正常 - proc 运行 18 秒,执行计划显示正确的实际行数。

编辑:正如 TrickyNixon 所建议的,这似乎是参数嗅探问题的标志。但实际上,我在这两种情况下都得到了完全相同的执行计划。相同的索引以相同的顺序使用。我看到的唯一区别是直接使用参数值时,PK_ED_Transitions 索引上的实际行数较高。

我已经完成了 dbcc dbreindex 和 UPDATE STATISTICS 没有任何成功。dbcc show_statistics 也显示了良好的索引数据。

proc 是用 RECOMPILE 创建的,因此每次运行时都会编译一个新的执行计划。

更具体地说 - 这个运行速度很快:

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

declare @local datetime
set @local = @Param

select 
some columns
from 
table1
where
column = @local
group by
some other columns

这个版本运行速度非常慢,但产生完全相同的执行计划(除了已用索引上的实际行数过高):

CREATE  Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE 
as

set nocount on

select 
some columns
from 
table1
where
column = @Param
group by
some other columns

有任何想法吗?有谁知道 Sql Server 在计算查询计划时从哪里获得实际的行计数值?

更新:我在另一台服务器上尝试了查询,将 copat 模式设置为 90(Sql2005)。它的行为相同。我想我会打开一个 ms 支持电话,因为这在我看来就像一个错误。

4

5 回答 5

6

好的,最后我自己解决了。

这两个查询计划在我起初错过的一个小细节上有所不同。慢的使用嵌套循环运算符将两个子查询连接在一起。这会导致索引扫描运算符的当前行数很高,这只是将输入 a 的行数与输入 b 的行数相乘的结果。

我仍然不知道为什么优化器决定使用嵌套循环而不是在这种情况下运行 1000 计时器更快的哈希匹配,但我可以通过创建一个新索引来处理我的问题,以便引擎执行索引查找 statt而不是嵌套循环下的索引扫描。

于 2008-10-23T11:30:47.583 回答
2

当您根据复制/粘贴查询检查存储过程的执行计划时,您使用的是估计计划还是实际计划?确保单击查询、包括执行计划,然后运行每个查询。比较这些计划,看看有什么不同。

于 2008-10-22T14:18:20.443 回答
1

这听起来像是参数嗅探的案例。这是一个很好的解释以及可能的解决方案: 我闻到一个参数!

这是解决它的另一个 StackOverflow 线程: SQL Server 中的参数嗅探(或欺骗)

于 2008-10-22T12:25:40.343 回答
0

对我来说,听起来好像统计数据不正确。重建索引不一定会更新它们。

您是否已经UPDATE STATISTICS为受影响的表尝试了显式?

于 2008-10-22T11:38:50.627 回答
0

您是否运行sp_spaceused来检查 SQL Server 是否为该表提供了正确的摘要?我相信在 SQL 2000 中,引擎在构建执行计划时会使用这种元数据。我们过去必须每周运行DBCC UPDATEUSAGE来更新一些快速变化的表上的元数据,因为 SQL Server 由于不正确的行计数数据而选择了错误的索引。

您正在运行 SQL 2005,并且 BOL 说在 2005 中您应该不必再运行 UpdateUsage,但由于您处于 2000 兼容模式,您可能会发现它仍然是必需的。

于 2008-10-22T19:46:54.057 回答