背景:我有一个供应商提供的 SQL Server 2012 数据库,因此对查询和表的修改是有限的。我们确实拥有数据库,因此我们可以添加和维护索引。
索引尚未维护或重建,因此有数百个索引处于 30% 以上的碎片化状态……这是我最初怀疑大量和持续使用 CPU 的原因,但在我们努力解决此问题的同时,我正在调查其他问题。
我没有看到任何明显的内存或磁盘 IO 压力。这是一个相对较少使用的 OLTP 系统,并且已经为资源提供了很好的配置......它真的不应该有任何问题,或者至少应该只有明显的峰值,没有持续的 CPU 使用。
两个问题:
整个数据库中过时的统计信息和高度碎片化的索引是否会导致 CPU 使用过多?
下面列出的来自该系统的等待统计信息的组合是否会使索引碎片的解释不可信?
信息:
WaitType Wait_S
--------------------------------- -----------
CXPACKET 773345.21
PAGELATCH_UP 737295.83
SOS_SCHEDULER_YIELD 140425.24
LATCH_EX 69877.95
RESOURCE_SEMAPHORE_QUERY_COMPILE 60985.48
LCK_M_SCH_S 39488.17
等待结果的来源查询:
WITH [Waits] AS
(
SELECT
[wait_type],
[wait_time_ms] / 1000.0 AS [WaitS],
([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS],
[signal_wait_time_ms] / 1000.0 AS [SignalS],
[waiting_tasks_count] AS [WaitCount],
100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage],
ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum]
FROM
sys.dm_os_wait_stats
WHERE
[wait_type] NOT IN (... common waits )
AND [waiting_tasks_count] > 0)
SELECT
MAX ([W1].[wait_type]) AS [WaitType],
CAST (MAX ([W1].[WaitS]) AS DECIMAL (16,2)) AS [Wait_S],
CAST (MAX ([W1].[ResourceS]) AS DECIMAL (16,2)) AS [Resource_S],
CAST (MAX ([W1].[SignalS]) AS DECIMAL (16,2)) AS [Signal_S],
MAX ([W1].[WaitCount]) AS [WaitCount],
CAST (MAX ([W1].[Percentage]) AS DECIMAL (5,2)) AS [Percentage],
CAST ((MAX ([W1].[WaitS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgWait_S],
CAST ((MAX ([W1].[ResourceS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgRes_S],
CAST ((MAX ([W1].[SignalS]) / MAX ([W1].[WaitCount])) AS DECIMAL (16,4)) AS [AvgSig_S]
FROM [Waits] AS [W1]
INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum]
GROUP BY [W1].[RowNum]
HAVING SUM ([W2].[Percentage]) - MAX ([W1].[Percentage]) < 95;
这是部分正确的。索引碎片不会导致高 CPU。内部碎片意味着页面上有很多可用空间,扫描索引将花费更多时间。这将导致更多的磁盘 IO 并需要更多的内存来存储索引(由于索引页中的可用空间),这意味着缓冲池中会浪费更多的空间。
错误的统计信息将导致查询优化器生成低效(错误)的计划,从而导致性能下降,例如,需要 2 秒才能完成的查询将需要 2 分钟或 2 小时等,因为 sql server 会做出错误的猜测(例如,将估计 1 行作为与实际的 2M 行相反)并且可能会选择执行大量读取的不合适的连接,或者可以选择错误的连接,例如嵌套循环,其中散列或合并连接本来是更好的选择。糟糕的(过时的或旧的)统计数据会使您的 CPU 处于更高的水平。
因此,对您的统计数据和索引进行碎片整理肯定会有所帮助。我建议您使用Ola 的 Index Maintenance 解决方案,而不是自己设计解决方案。
请参阅 Kendra 的精彩帖子:为什么索引碎片和不良统计信息并不总是问题(视频)?
Remus Rusanu 有一篇非常好的博客文章:The Bizzaro Guide to SQL Server Performance (注意:不要遵循它!)
我相信在您的 sql server 配置级别可能有更多的事情需要解决,而不仅仅是担心索引碎片。另外 CXPACKET 等待本身不是问题。
要检查的事情:
optimize for ad hoc workloads
您可以使用Glenn Berry 的诊断查询 - 2012 版
和
此外,Joe Sack 还谈到了 SQL Server CPU 性能问题的故障排除方法