【问题标题】:Why do statistics get out of date so quickly in SQL Server?为什么 SQL Server 中的统计信息过时如此之快?
【发布时间】:2011-05-28 13:12:52
【问题描述】:

我们有一个有点复杂的 SQL 更新查询,每月运行几次。大多数时候它似乎运行得非常快,但在某些数据库上,它需要很长时间。在涉及的表上运行“UPDATE STATISTICS”后,更新立即再次快速运行。我们最终设置了一个夜间任务,它在数据库中的所有表上调用 UPDATE STATISTICS。但这似乎并没有解决问题。我们最终还是不得不每次手动运行“更新统计”。为什么统计数据会这么快过时?

查询大致如下:

UPDATE DataTableA
SET DataTableA.IndexedColumn1 = 123456789, DataTableA.Flag1 = 1
FROM DataTableA WITH (INDEX(IX_DataTableA))
INNER JOIN GroupingTableA ON GroupingTableA.ForeignKey1 = GroupingTableA.PrimaryKey
INNER JOIN LookupTableA ON DataTableA.ForeignKey3 = LookupTableA.PrimaryKey
LEFT OUTER JOIN GroupingTableB ON DataTableA.IndexedColumn2 = GroupingTableB.IndexedColumn2
WHERE GroupingTableB.IndexedColumn1 = 123456789
AND DataTableA.IndexedColumn1 IS NULL
AND DataTableA.IndexedColumn2 IN ( ... 300 entries here ... )
AND DataTableA.Deleted = 0
AND GroupingTableA.Date <= GroupingTableB.EndDate
AND GroupingTableA.Date >= DATEADD(month, -1, GroupingTableB.StartDate)
AND LookupTableA.Column2 = 1
AND DataTableA.Status1 IN (1, 3)
AND DataTableA.Status2 NOT IN (1, 3, 9)

DataTableA 包含数百万行。
GroupingTableA 和 GroupingTableB 各包含数万行。
LookupTableA 包含几十行。
索引 IX_DataTableA 是 (IndexedColumn1 ASC, IndexedColumn2 ASC) 上的索引

【问题讨论】:

  • 经过反复试验,我们确定上例中的 GroupingTableB 已经过时了。问题仍然存在,但我们通过在每次插入该表时调用该表的“UPDATE STATISTICS”来解决它。不完全是理想的解决方案...
  • 我知道这个问题已经过时了,但就其价值而言,当您在 WHERE 子句中对GroupingTableB 设置条件时,它会在逻辑上将其LEFT JOIN 转换为INNER JOIN。你有3个这样的条件。如果您希望LEFT JOIN 实际上充当正确的OUTER 连接,则必须将这些条件移至LEFT JOIN 中的ON 子句。我只是说... :)

标签: sql-server sql-server-2000 statistics


【解决方案1】:

如果您强制它使用特定索引,我认为您的统计数据不会那么重要 (WITH (INDEX(IX_DataTableA))

你确定你比优化器更了解吗?

我将从查看快速更新和慢速更新的执行计划开始。此外,快/慢查询的更新记录数是否可比?

【讨论】:

  • 很好的电话@Abe Miessler - @Bryce Wagner 在更新统计信息后可能会看到改进,因为 UDPATE 使用了新的执行计划。
  • 在这种情况下,是的,我确信我比优化器更清楚,在某些情况下,它正在对完全不相关的索引进行索引扫描。包括 WITH INDEX 修复了大多数优化器问题,我只是很困惑为什么它没有解决所有问题。
  • 当它运行缓慢时,我确实查看了估计的执行计划,它说它预计有 92% 的时间在我的强制索引上进行索引搜索。
  • 这是有道理的。并不意味着使用不同的索引它不会运行得更快...
【解决方案2】:

当自动统计开启时,引擎想要更新统计quite often,通常比每晚更频繁:

 Table Type | Empty Condition | Threshold When Empty |Threshold When Not Empty 
_________________________________________________________________________________
 Permanent  | < 500 rows      | # of Changes >= 500  | # of Changes >= 500 + (20% of Cardinality)
___________________________________________________________________________
 Temporary  | < 6 rows        | # of Changes >= 6    | # of Changes >= 500 + (20% of Cardinality)

但为什么不排除猜测并简单地部署计划指南呢?见Understanding Plan Guides

【讨论】:

  • 我在第一个链接中使用了“sp_autostats , , ”,以确保在索引上打开了统计信息。我还运行了“sp_dboption ,'auto create statistics','on'”,以确保它们实际上是打开的(即使这些框已被选中)。如果下周表现不佳,我会考虑制定一份计划指南。
  • 搞乱自动统计标志没有任何效果,所以我开始研究计划指南。原来它们只适用于 SQL 2005 及更高版本,而不是 2000。所以不要继续下去。
猜你喜欢
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多