截断表和更新统计信息
Posted
技术标签:
【中文标题】截断表和更新统计信息【英文标题】:Truncate Table and UPDATE Statistics 【发布时间】:2009-11-13 16:15:01 【问题描述】:在调用 Truncate table 后是否需要更新表统计信息或自动更新?
问:我们需要在截断表后调用“UPDATE STATISTICS”吗?
【问题讨论】:
【参考方案1】:在再次需要统计信息之前,统计信息不会自动更新。又名,TRUNCATE 不这样做。 所以“不”。
最初的答案是“是”,因为它不是作为 TRUNCATE 的一部分自动执行的。这取决于您如何阅读问题:-)
请记住,当查询需要时(例如行更改的数量),统计信息会自动更新。来自 BOL 中的“Index Statistics”
只要查询执行计划中使用的统计信息未能通过当前统计信息的测试,就会启动统计信息更新
一种使用STATS_DATE进行验证的方法...
SELECT
name AS index_name,
STATS_DATE(object_id, index_id)
FROM
sys.indexes
WHERE
object_id = OBJECT_ID('MyTruncatedTable')
编辑:我想确定 :-)
您会看到统计信息仅由 SELECT 语句更新,而不是 INSERT、DELETE 或 TRUNCATE
IF OBJECT_ID('dbo.foo') IS NOT NULL DROP TABLE dbo.foo
CREATE TABLE dbo.foo (
bar int NOT NULL IDENTITY (1, 1) PRIMARY KEY,
thing int NOT NULL
)
CREATE INDEX IX_thing ON dbo.foo (thing)
INSERT dbo.foo (thing) SELECT c1.object_id FROM sys.columns c1, sys.columns c2
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS AfterLoad
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
SELECT DISTINCT thing FROM dbo.foo ORDER BY thing DESC
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS AfterFirstQuery
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
DELETE TOP (50000) dbo.foo
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS AfterDelete
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
SELECT DISTINCT thing FROM dbo.foo ORDER BY thing DESC
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS After2ndQuery
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
TRUNCATE TABLE dbo.foo
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS AfterTruncate
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
SELECT DISTINCT thing FROM dbo.foo ORDER BY thing DESC
SELECT
name AS index_name,
STATS_DATE(object_id, index_id) AS After3rdQuery
FROM sys.indexes WHERE object_id = OBJECT_ID('dbo.foo')
【讨论】:
@gbn:我按原样执行了这个查询。它正在运行最后 12 分钟。它卡在某个锁里了吗?需要多少时间?我想我现在需要杀了它。 抱歉,它在我的 Virtual PC SQL 2008 实例上运行了 10 秒。我的数据库虽然是空的,但提供了 238k 行,所以它可能只是太多行...... @gbn:好的。它终于在 12:25 分钟后执行完毕。根据这个统计数据在删除或截断后都没有更新。所以看来我需要调用“更新统计”。对吗? 不需要,引擎会在下一次SELECT时意识到这一点 非常感谢。只是想确保它不会让以后提到这个问题的人感到困惑:)【参考方案2】:这取决于您的管理员如何配置统计信息。通常的方法是每周进行一次维护工作。然后您可以等待作业运行,或手动更新统计信息。
还有automatically update statistics的选项:
当自动更新统计 选项 AUTO_UPDATE_STATISTICS 已打开, 查询优化器确定何时 统计数据可能已过时并且 然后在使用时更新它们 通过查询。
这可能会在截断后重新计算。
您可以开启自动更新,例如:
ALTER DATABASE AdventureWorks
SET AUTO_UPDATE_STATISTICS ON;
手动到update statistics:
UPDATE STATISTICS Sales.SalesOrderDetail
要验证统计信息的当前年龄,请运行:
SELECT
object_name = Object_Name(ind.object_id),
IndexName = ind.name,
StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
FROM SYS.INDEXES ind
order by STATS_DATE(ind.object_id, ind.index_id) desc
【讨论】:
(+1) 谢谢安多玛。将自动更新统计信息保留在……或者我们可以默认保留它有什么缺点吗?我怎么知道它是否在我的系统上? (对不起,我不是管理员,但我拥有所有访问权限) @noob2487:自动更新统计信息可能会影响性能。例如,如果您在更新大表时负载很高,那么更新统计信息会增加更多负载。但是,在 99% 的情况下,启用自动更新是一个很好的选择。 知道了。就我而言,在截断这些表之后,我有大约 100K 记录要加载。所以更好的是我将禁用自动更新。有没有办法查看它是启用还是禁用?【参考方案3】:由于您没有数据,因此在插入数据之前将毫无意义,然后您会寻求更新统计信息。
不要忘记您可以自动更新统计数据以及每天/每周运行和更新统计作业等...
如果仍然存在重大问题,只需截断然后更新表格上的统计信息。
【讨论】:
(+1) 是的,没错。由于没有数据,统计数据将毫无意义,或者您可以说它们是“不正确的”。所以,我担心一旦我开始在表中插入数据,这些不正确的统计数据会如何影响性能。 引擎会查看统计数据来制定计划。只有当它实际尝试运行它并且……没有找到数据时,它才会看到精心设计的计划是“毫无意义的”。所以统计信息对于空表来说非常重要:是告诉优化器该表为空的统计信息。以上是关于截断表和更新统计信息的主要内容,如果未能解决你的问题,请参考以下文章