Tom*_*Tom 7 performance sql-server-2008-r2 wait-types performance-tuning
最近,我们的一台服务器出现了 CPU 问题,在调查此问题的同时,我们也注意到查询运行缓慢,等待PAGEIOLATCH_XX
. 特别是,重新索引作业似乎总是具有这种等待类型。
作为回应,我运行了一个收集sys.dm_io_virtual_file_stats
,然后将其分解为时间块并计算出每个操作的平均停顿。虽然主要是尖峰,但磁盘似乎有规律地低于 20 毫秒的值。据我所知,20 毫秒是推荐值(?)。
除此之外,我还运行了 Glenn Barry 的脚本:
select db_name(database_id) as DatabaseName, file_id
,io_stall_read_ms
,num_of_reads
,cast(io_stall_read_ms/(1.0+num_of_reads) as numeric(10,1)) as 'avg_read_stall_ms'
,io_stall_write_ms
,num_of_writes
,cast(io_stall_write_ms/(1.0+num_of_writes) as numeric(10,1)) as 'avg_write_stall_ms'
,io_stall_read_ms + io_stall_write_ms as io_stalls
,num_of_reads + num_of_writes as total_io
,cast((io_stall_read_ms+io_stall_write_ms)/(1.0+num_of_reads +
num_of_writes) as numeric(10,1)) as 'avg_io_stall_ms'
from sys.dm_io_virtual_file_stats(null,null) --where db_name(database_id) = 'tempdb'
order by [DatabaseName] desc'
Run Code Online (Sandbox Code Playgroud)
它还计算平均 I/O 停顿,这也确认停顿时间小于 20 毫秒。
我还查看了以下内容,看看是否有任何挂起的任务花费的时间比建议的要长,但这并没有抛出任何挂起的 I/O 操作的时间通常超过 20 毫秒。
SELECT db_name(database_id) as 'Database',
file_name(file_id) as 'File',
io_stall,
io_pending_ms_ticks
FROM sys.dm_io_virtual_file_stats(NULL, NULL) iovfs,
sys.dm_io_pending_io_requests as iopior
WHERE iovfs.file_handle = iopior.io_handle
Run Code Online (Sandbox Code Playgroud)
我现在的问题是:如果问题与磁盘无关,为什么我会看到很多 PAGEIOLATCH_XX 等待?特别是,为什么这种等待类型的重新索引运行速度非常慢?
这可能与CPU压力有关吗?
================================================== ==============================
我只是想更新线程。在做了更多的分析之后,我找到了一个导致大量读取的特定过程。过程如下:
ALTER PROCEDURE [dbo].[GetActiveSessionCount]
@SessionCount INTEGER OUTPUT
AS
SET NOCOUNT ON
BEGIN
DECLARE @Error INTEGER,
@RowCount INTEGER,
@nExpireAfter INTEGER
SELECT @nExpireAfter = ExpireSessionsAfter FROM KSYSTEM
SELECT @Error = @@ERROR, @RowCount = @@ROWCOUNT
IF(1 <> @RowCount)
BEGIN
RAISERROR (50003, 15, 1, 'GetActiveSessionCount')
RETURN 50003
END
IF (0 <> @Error)
BEGIN
RETURN @Error
END
SELECT @SessionCount = COUNT(SessionID)
FROM KSESSION WITH (NOLOCK)
WHERE
(
(
Expirable = 0
)
OR
(
Expirable = 1
AND
( --SessionID IS NOT NULL)
EXISTS (SELECT SessionID FROM KFILESAWAITINGCOMMIT fac WITH (NOLOCK) WHERE SessionID = fac.SessionID)
OR
(
LastAccessDateTime IS NOT NULL
AND GETDATE() <= (DATEADD(minute, @nExpireAfter, LastAccessDateTime))
)
)
)
)
SELECT @Error = @@ERROR
IF(@Error <> 0)
BEGIN
RETURN @Error
END
RETURN 0
END
Run Code Online (Sandbox Code Playgroud)
使用STATISTICS IO
我可以看到问题行是
SELECT SessionID FROM KFILESAWAITINGCOMMIT fac WITH (NOLOCK) WHERE SessionID = fac.SessionID
Run Code Online (Sandbox Code Playgroud)
查看执行计划,它正在执行聚集索引扫描。现在,该表上有一个非聚集索引,已经专门用于 SessionID,但是它没有被使用。
我在测试中发现的是,如果我自己运行它SELECT
,那么它使用非聚集索引并且性能良好。但是如果我在 proc 中使用一个提示来强制它使用非聚集索引,那么它实际上会表现得更糟。
谁能解释一下?
当 SQL Server 等待从磁盘读取数据时,会记录 PAGEIOLATCH_XX 等待。索引维护是一项众所周知的密集操作,因此应该在最安静的时间执行,以避免对生产产生任何影响。
您提到您的查询导致了相同的等待。如果这与索引维护同时发生,那么这并不奇怪,但如果它发生在其他时间,则可能是由于内存压力(RAM 中没有足够的空间来存储页面,因此需要再次从磁盘读取它们) )、大型扫描,甚至可能表明您的磁盘存在潜在问题。需要更多的调查来排除这些可能性。