SQL Server如何计算出估计的行数?

时间:2009-09-25 11:13:39

标签: sql-server sql-server-2005 sql-execution-plan

我正在尝试调试一个相当复杂的存储过程,它连接多个tabls(10-11)。我看到,对于树的一部分,估计的行数与实际行数大不相同 - 在最差的SQL服务器估计将返回1行,而实际上返回55,000行!

我正在尝试找出原因 - 我的所有统计信息都是最新的,并且我已经在几个表上使用FULLSCAN更新了统计信息。我没有使用任何用户定义的函数或表变量。据我所知,SQL服务器应该能够准确估计将返回多少行,但它会继续选择一个计划,以便它执行数万次RDI查找(当它只期望执行1次时)或2)。

我可以做些什么来尝试理解为什么估计的行数超出了这么多?

更新:所以看一下这个计划,我发现了一个特别令人怀疑的节点 - 它使用以下预测表在表上进行表扫描:

status <> 5
AND [type] = 1
OR [type] = 2

这个谓词返回整个表(630行 - 表扫描本身它不是性能不佳的来源)但是SQL服务器的估计行数只有37个。然后SQL服务器继续执行几个嵌套循环这适用于RDI查找,索引扫描和索引搜索。这可能是我大量错误计算的根源吗?如何让它估计更合理的行数?

4 个答案:

答案 0 :(得分:8)

SQL Server使用以下数据(来自here)将每个索引拆分为最多200个范围:

  
      
  • RANGE_HI_KEY

         

    显示直方图步骤上边界的键值。

  •   
  • RANGE_ROWS

         

    指定范围内的行数(它们小于此RANGE_HI_KEY,但大于之前的较小RANGE_HI_KEY)。

  •   
  • EQ_ROWS

         

    指定完全等于RANGE_HI_KEY的行数。

  •   
  • AVG_RANGE_ROWS

         

    范围内每个不同值的平均行数。

  •   
  • DISTINCT_RANGE_ROWS

         

    指定此范围内有多少个不同的键值(不包括RANGE_HI_KEYRANGE_HI_KEY之前的上一个键);

  •   

通常,大多数填充值会进入RANGE_HI_KEY

然而,它们可能会进入范围,这可能导致分布的偏差。

想象一下这些数据(以及其他数据):

键值行数

1          1
2          1
3          10000
4          1

SQL Server通常构建两个范围:134到下一个填充值,这会产生以下统计信息:

RANGE_HI_KEY  RANGE_ROWS  EQ_ROWS  AVG_RANGE_ROWS  DISTINCT_RANGE_ROWS
3             2           10000    1               2

,这意味着在搜索2时,只有1行,最好使用索引访问。

但如果3进入范围内,则统计数据如下:

RANGE_HI_KEY  RANGE_ROWS  EQ_ROWS  AVG_RANGE_ROWS  DISTINCT_RANGE_ROWS
4             10002       1        3334            3

优化器认为密钥33342行,索引访问太贵。

答案 1 :(得分:3)

它使用统计数据,它为每个索引保留。

(您还可以创建非索引列的统计信息)

更新数据库中每个表的所有统计信息(警告:在非常大的数据库上需要一些时间。如果不检查DBA,请不要在生产服务器上执行此操作...) :

exec sp_msforeachtable 'UPDATE STATISTICS ?'

如果您没有正常的预定作业来重建最活跃的索引(即大量的INSERTS或DELETES),您应该考虑重建索引(与上述相同的警告):

exec sp_msforeachtable "DBCC DBREINDEX('?')"

答案 2 :(得分:0)

由于您已经更新了统计信息,我会尝试消除任何参数嗅探:

CREATE PROCEDURE xyz
(
    @param1 int
    ,@param2 varchar(10)

)AS

DECLARE @param_1 int
       ,@param_2 varchar(10)

SELECT @param_1=@param1
      ,@param_2=@param2

...complex query here....
...WHERE column1=@param_1 AND column2=@param_2....

go

答案 3 :(得分:0)

重建索引可能会解决错误的估计行值问题