Wir hatten in letzter Zeit CPU-Probleme mit einem unserer Server, und während wir uns damit befassten, haben wir auch festgestellt, dass Abfragen langsam und mit Wartezeiten von ausgeführt werden PAGEIOLATCH_XX
. Insbesondere ein Neuindizierungsjob hat anscheinend immer diesen Wartetyp.
Als Reaktion darauf habe ich eine Sammlung durchgeführt sys.dm_io_virtual_file_stats
und diese dann in Zeitabschnitte unterteilt und den durchschnittlichen Stall pro Operation berechnet. Während es meistens Spitzen gibt, scheint die Platte einen Wert von regelmäßig unter 20 ms zu haben. Soweit ich mich erinnere, ist 20 ms der empfohlene Wert (?).
Darüber hinaus habe ich Glenn Barrys Skript ausgeführt:
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'
Dies berechnet auch den durchschnittlichen E / A-Stillstand und bestätigt auch Stillstände von weniger als 20 ms.
Ich habe auch im Folgenden nachgesehen, ob ausstehende Aufgaben länger dauern als empfohlen, aber dies führt nicht zu ausstehenden E / A-Vorgängen, die regelmäßig länger als 20 ms dauern.
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
Meine Frage lautet jetzt: Wenn das Problem nicht mit der Festplatte zusammenhängt, warum werden dann viele PAGEIOLATCH_XX-Wartezeiten angezeigt? Warum läuft der Reindex bei diesem Wartetyp extrem langsam?
Könnte dies mit dem CPU-Druck zusammenhängen?
================================================== ==============================
Ich wollte nur den Thread aktualisieren. Nachdem ich weitere Analysen durchgeführt habe, habe ich einen bestimmten Prozess aufgespürt, der signifikante Lesevorgänge verursacht. Der Prozess ist wie folgt:
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
Mit STATISTICS IO
Ich kann ich sehen, dass die Problemlinie ist
SELECT SessionID FROM KFILESAWAITINGCOMMIT fac WITH (NOLOCK) WHERE SessionID = fac.SessionID
Mit Blick auf den Ausführungsplan wird ein Clustered Index Scan durchgeführt. Jetzt gibt es für diese Tabelle bereits einen nicht gruppierten Index speziell für SessionID, der jedoch nicht verwendet wird.
Was ich beim Testen finde, ist, wenn ich das SELECT
alleine ausführe, dann verwendet es den nicht gruppierten Index und funktioniert gut. Wenn ich jedoch einen Hinweis im Prozess verwende, um die Verwendung des nicht gruppierten Index zu erzwingen, ist die Leistung tatsächlich schlechter.
Kann jemand erklären?