问题描述:
?
在对OLTP系统的一个上千万的表做归档后,循环分批删除源表数据时,业务应用收到超时告警,如下:
?
V1.1.1.1: ****Process - QueryTransactionFor****: 23075129
Timeout expired. ?
The timeout period elapsed prior to completion of the operation or the server is not responding. ?
This failure occured while attempting to connect to the Principle server.
?
查询当前活跃进程,发现一个极慢的StatMan查询:
?
SELECT StatMan([SC0], [SC1], [SB0000])
FROM (SELECT TOP 100 PERCENT [SC0], [SC1], step_direction([SC0]) over (order by NULL) AS [SB0000] FROM (SELECT [TransactionID] AS [SC0],
[ID] AS [SC1]
FROM [dbo].[Product] TABLESAMPLE SYSTEM (8.340078e-001 PERCENT) WITH (READUNCOMMITTED) ) AS MS_UPDSTATS_TBL_HELPER ORDER BY [SC0], [SC1], [SB0000] ) AS
MS_UPDSTATS_TBL OPTION (MAXDOP 1)
?
?
这是一个统计信息维护任务,来看看该表所有的统计信息。 ??
?
EXEC sp_autostats 'dbo.Product'; ? ?
GO
?
将结果集根据时间降序排列显示,如下:
?
[IX_Product_TransactinID] ON 2015-11-12 14:15:14
[IX_Product_CreateTime] ON 2015-11-12 10:17:50
[IX_Product_Number] ON 2015-10-23 12:10:51
[PK_Product] ON 2015-08-14 20:03:41
[_WA_Sys_0000000E_693CA210] ON 2015-07-03 10:39:36
[_WA_Sys_00000025_693CA210] ON 2014-12-05 16:22:20
[_WA_Sys_0000002A_693CA210] ON 2014-12-05 14:54:53
[_WA_Sys_0000000B_693CA210] ON 2014-07-01 10:52:54
[_WA_Sys_00000018_693CA210] ON 2013-01-24 02:16:11
[_WA_Sys_00000023_693CA210] ON 2012-12-20 13:17:27
[_WA_Sys_00000026_693CA210] ON 2012-12-20 13:17:26
[_WA_Sys_00000004_693CA210] ON 2012-12-20 13:17:25
[_WA_Sys_00000006_693CA210] ON 2012-12-20 13:17:24
[_WA_Sys_00000022_693CA210] ON 2012-12-20 13:17:23
[_WA_Sys_0000001B_693CA210] ON 2012-12-20 13:17:22
[_WA_Sys_0000001D_693CA210] ON 2012-12-20 13:17:21
[_WA_Sys_0000000F_693CA210] ON 2012-12-20 13:17:20
[_WA_Sys_00000013_693CA210] ON 2012-12-20 13:17:18
?
?
看到在当前时间点,索引[IX_Product_TransactinID]在更新统计信息。
?
在监控到StatMan进程的同时,也看到导致业务告警的一个查询极慢。
?
SELECT ? ?
? ? p.[ID] ? ?
? ? ,p.[Name] ? ?
? ? ,p.[Price] ? ?
? ? ,p.[Amount] ? ?
? ? ,p.[TransactionID] ? ?
? ? ,t.[Action] ? ?
? ? ,t.[TransactionStatus] ? ?
? ? ,t.[TransactionResult] ? ?
FROM [Product] AS p LEFT JOIN [TransactionInfo] AS t ON p.[TransactionID] = t.[ID] ? ?
WHERE [TransactionID] = @transactionId
?
可以明确是因为删除Product表的数据,使得[TransactionID]列索引[IX_Product_TransactinID]达到了要更新统计信息的阈值,触发了索引维护。
?
问题处理:
为了让问题查询得到尽快恢复,我新建了一个[TransactionID]列索引,将[IX_Product_TransactinID]禁用,问题得到临时解决。
?
原理分析:
?
统计信息维护策略
当SQL Server需要去估算某个操作的复杂度时,它必定要试图去寻找相应的统计信息做支持。
数据库管理员无法预估SQL Server会运行什么样的操作,所以也无法预估SQL Server可能会需要什么样的统计信息。如果靠人力来建立和维护统计信息,那将是一个非常复杂的工程。好在SQL Server不是这样设计的。在绝大多数情况下,SQL Server自己会很好地维护和更新统计信息,用户基本没有感觉,
数据库管理员也没有额外的负担。
?
这主要是因为在SQL Server数据库属性里,有两个默认打开的设置:Auto Create Statistics和Auto Update Statistics。它们能够让SQL Server在需要的时候,自动建立要用到的统计信息,也能在发
现统计信息过时的时候,自动去更新它。
?
SQL Server会在什么情形下创建统计信息呢?主要有3种情况:
1.在索引创建时,SQL Server会自动地在索引所在的列上创建统计信息
所以从某种角度讲,索引的作用是双重的,它自己能够帮助SQL Server快速找到数据。而它上面的统计信息,也能够告诉SQL Server数据的分布情况。
?
2.管理员也可以通过CREATE STATISTICS之类的语句手动创建他认为需要的统计信息
如果打开了Auto Create Statistics,一般来讲很少需要手动创建。
?
3.当SQL Server想要使用某些列上的统计信息,发现没有的时候,“Auto Create Statistics”会让SQL Server自动创建统计信息。
?
例如,当语句要在某个(或者某几个)字段上做过滤,或者要拿它(们)和另外一张表做连接(Join),SQL Server要估算最后从这张表会返