Es gibt eine Tabelle (SQL Server 2008 R2), die das Up/Down-Protokoll für mehrere Server enthält. Die Server werden in regelmäßigen Abständen gepingt und ihr Status (hoch oder runter) wird in diese Tabelle geschrieben. Es hat eine Struktur wie folgt aus:Ermitteln der Downtime-Dauer in der Serverprotokolltabelle
CREATE TABLE StatusLog
(
LogID INT PRIMARY KEY,
ServerID INT,
QueryDate DATETIME,
ServerStatus VARCHAR(50)
)
Beispieldaten
INSERT INTO StatusLog
VALUES
(1, '1724', '2016-04-16 09:28:00.000', 'up'),
(2, '1724', '2016-04-16 09:29:00.000', 'up'),
(3, '1724', '2016-04-16 09:30:00.000', 'down'),
(6, '1724', '2016-04-16 09:31:00.000', 'down'),
(8, '1724', '2016-04-16 09:32:00.000', 'down'),
(9, '1724', '2016-04-16 09:33:00.000', 'down'),
(17, '1724', '2016-04-16 09:33:40.000', 'up'),
(18, '1724', '2016-04-16 09:34:00.000', 'up')
Ich versuche Gesamtausfallzeit für einen bestimmten Server für einen bestimmten Zeitraum zu finden. Im obigen Datenextrakt wird der Status des Servers mit der ID 1724 um 09:30:00 "down" und wechselt um 09:33:40 Uhr zurück zu "up", was einer Gesamtausfallzeit von 220 Sekunden entspricht.
Mein Ansatz ist:
- Für jeden "down-Block", finden die "down" Aufzeichnungen und setzen ihre QueryDate als nach unten Startzeit in einer neuen Spalte. Das ist schnell.
- Suchen Sie in einer weiteren neuen Spalte den ersten "nach oben" -Datensatz nach dieser Startzeit und legen Sie das QueryDate als Ende der Ausfallzeit fest. Das ist ziemlich schnell.
- Tun Sie dies jedoch nur für den ersten Down Record im Down Block und nicht für andere Downs im Down Block, sonst berechnen Sie die Ausfallzeit mehrfach falsch. Um dies zu tun, muss ich mir die Zeilennummern ansehen und hier werden die Dinge unordentlich und langsam.
- Schließlich extrahieren Sie sie voneinander und Sie haben Ausfallzeit für diesen Block
- Summe alle Down-Zeiten, um die gesamte Stillstandszeit zu finden.
Ich schrieb die unten stehende Skript, aber es ist schrecklich langsam ist (Jeder Server Hunderttausende von Protokollaufzeichnungen hat)
DECLARE @StartDate DATE = '2016-04-01'
DECLARE @EndDate DATE = '2016-04-30'
DECLARE @ServerID INT = '1724'
;WITH CTE_StatusLog AS
(
SELECT LogID, QueryDate, ServerStatus,
ROW_NUMBER() OVER (ORDER BY QueryDate) AS RN
FROM StatusLog
WHERE ServerID = @ServerID
AND QueryDate BETWEEN @StartDate AND @EndDate
)
SELECT LogID,
QueryDate,
ServerStatus,
RN,
DownStarted = CASE WHEN s1.ServerStatus = 'down'
THEN s1.QueryDate END,
DownEnded = (SELECT TOP 1 QueryDate
FROM CTE_StatusLog AS s2
WHERE s2.QueryDate > s1.QueryDate
AND s1.ServerStatus = 'down'
AND s2.ServerStatus = 'up'
AND (SELECT s3.ServerStatus
FROM CTE_StatusLog AS s3
WHERE s3.RN = s1.RN-1) <> 'down'
ORDER BY s2.QueryDate),
DownDuration = DATEDIFF(SECOND,
CASE WHEN s1.ServerStatus = 'down'
THEN s1.QueryDate END,
(SELECT TOP 1 QueryDate
FROM CTE_StatusLog AS s2
WHERE s2.QueryDate > s1.QueryDate
AND s1.ServerStatus = 'down'
AND s2.ServerStatus = 'up'
AND (SELECT s3.ServerStatus
FROM CTE_StatusLog AS s3
WHERE s3.RN = s1.RN-1) <> 'down'
ORDER BY s2.QueryDate))
FROM CTE_StatusLog AS s1
WHERE QueryDate BETWEEN @StartDate AND @EndDate
ORDER BY s1.RN
Der Ausgang:
LogID QueryDate ServerStatus RN DownStarted DownEnded DownDuration
1 2016-04-16 09:28:00.000 up 1 NULL NULL NULL
2 2016-04-16 09:29:00.000 up 2 NULL NULL NULL
3 2016-04-16 09:30:00.000 down 3 2016-04-16 09:30:00.000 2016-04-16 09:33:40.000 220
6 2016-04-16 09:31:00.000 down 4 2016-04-16 09:31:00.000 NULL NULL
8 2016-04-16 09:32:00.000 down 5 2016-04-16 09:32:00.000 NULL NULL
9 2016-04-16 09:33:00.000 down 6 2016-04-16 09:33:00.000 NULL NULL
17 2016-04-16 09:33:40.000 up 7 NULL NULL NULL
18 2016-04-16 09:34:00.000 up 8 NULL NULL NULL
Wie kann ich dies verbessern Skript oder gibt es eine bessere Möglichkeit, Ausfallzeiten in Bezug auf diese Tabellenstruktur zu berechnen?
Schöne Antwort. Ich denke, du musst die Gruppe um down_in_seconds entfernen und stattdessen das mit einem 'MAX (...)' –
@JamieF aggregieren. . . Ja. Das nächste Datum kann in der "Gruppe von" sein, aber die zweite Änderung in jeder Zeile. Du hast recht. –
Äußere Anwendung half sehr, danke. –