Blog

SQL-Server Fehleranalyse

Rainer
IT-Consultant

Microsoft bietet verschiedene Möglichkeiten, Fehler- und Ereignisprotokolle aufzulisten. Die vermutlich bekannteste dürfte der Windows Event-Viewer bzw. die Windows Ereignisanzeige sein die den Zugriff auf viele Log-Dateien erlaubt, u.a. auf solche in dem Verzeichnis C:\Windows\System32\winevt\Logs, und in der folgenden Abbildung dargestellt ist.

Im SQL Server Umfeld gibt es drei weitere Möglichkeiten, nämlich

  1. im Management-Studio den Management-Knoten mit seinem Unterknoten “SQL Server Logs” und als Unterknoten das aktuelle (Current) und die archivierten Logs (Archive #1, …, Archive #6 - …). Über einen Doppelklick auf den jeweiligen Knoten wird die entsprechende Log-Datei mit dem Logfile Viewer geöffnet.
  1. Eine entsprechende Struktur im Agent-Teilbaum für die Agent-Protokolle. Auch hier wird die entsprechende Protokolldatei durch Doppelklick mit dem Logfile Viewer geöffnet.
  1. die Stored Procedure sp_readerrorlog.

sp_readerrorlog

Wie man dem Namen und den Microsoft Benennungskonventionen für Datenbankobjekte entnehmen kann, handelt es sich hier um eine Stored Procedure. sp_readerrorlog ist eine Systemprozedur über die man auf die SQL Server Ereignisprotokolle zugreifen kann. Genauer führt diese Prozedur zunächst eine Berechtigungsprüfung durch und führt anschließend die eigentliche (extended) Stored Procedure xp_readerrorlog aus, im Endeffekt eine DLL, die den Zugriff auf die Protokolldatei durchführt. Hierbei werden die an sp_readerrorlog übergebenen Parameter je nach Aufruf an xp_readerrorlog weitergegeben.

Parameter

Die folgende Abbildung zeigt die Schnittstelle der Stored Procedure sp_readerrorlog aus dem Objektbaum des Management Studios unter Databases ==> System Databases== > master ==> Programmability== > Stored Procedures ==> System Stored Procedures

Parameter “@p1”

Dieser Parameter wird in der Microsoft Dokumentation mit “log_number” bezeichnet und gibt die Nummer der gewünschten Protokolldatei an. Hierbei steht “0” für das aktuelle Protokoll (“Current”), “1” für das vorhergehende (“Archive #1) usw..

Der Default-Wert für diesen Parameter ist “0”.

Parameter “@p2”

Dieser Parameter wird in der Microsoft Dokumentation mit product ID bezeichnet und darf lediglich die folgenden beiden Werte annehmen

  • “1” für das SQL Server Protokoll (default)
  • “2” für das Agent Protokoll

Die Protokolldaten sind i.d.R. sehr umfangreich und dadurch unübersichtlich. Sehen Sie sich an dieser Stelle gerne die aktuellen Protokolldaten Ihres SQL Servers durch Doppelklick auf den “Current”-Knoten (vgl. Abb. oben) an. Aus diesem Grund existieren zwei weitere optionale Parameter über die eine rudimentäre Filterung erfolgen kann, nämlich:

Parameter “@p3”

Dieser Parameter wird in der Microsoft Dokumentation mit string_to_search bezeichnet. Er bietet die Möglichkeit, das gewählte Protokoll bezüglich einer Zeichenkette zu filtern. Die Suche erfolgt case-insensitiv.

Der Default-Wert für diesen Parameter ist “0”.

Parameter “@p4”

Dieser Parameter bietet die Möglichkeit einen weiteren Suchfilter zu spezifizieren.

Der Default-Wert für diesen Parameter ist “0”.

Wird der Parameter @p3 verwendet, so muss auch der Parameter @p2 angegeben werden. Werden die Parameter @p3 und @p4 verwendet so werden diese bei der Suche mit einem logischen UND verknüpft.

Aufrufbeispiele für sp_readerrorlog

exec sp_readerrorlog 1 -- Anzeige der aktuellen Agent-Protokolldatei
exec sp_readerrorlog 0, 1 -- Anzeige der neuesten archivierten SQL Server Protokolldatei
exec sp_readerrorlog 0,NULL,'Microsoft SQL Server','Registry' -- Die Parameter @p3 und @p4 werden
-- nicht verwendet, vermutlich ein Bug beim Aufruf von xp_readerorlog().
exec sp_readerrorlog 0,1,'Microsoft SQL Server','Registry' -- Anzeige derjenigen Zeilen der
-- aktuellen SQL Server Protokolldatei die sowohl den Text "Microsoft SQL Server" als auch den Text "Registry" enthalten

Wie es besser geht

Die Verwendung der o.a. Filterparameter @p3 und @p4 kann praktisch sein, ist aber in vielen Fällen zu stark eingeschränkt, da nur eine UND-Verknüpfung möglich ist. Eine weitaus bessere Möglichkeit lässt sich erreichen, wenn man die ungefilterten Protokolleinträge in eine temporäre Tabelle schreibt und anschließend die Filterung über das where-Kriterium eines select-Statements verwendet. Hierbei können dann auch Protokolleinträge mitselektiert werden, die zwar nicht das gewünschte Textmuster enthalten, sondern zum gleichen Zeitpunkt und von dem selben Prozess protokolliert wurden wie die Einträge mit dem abgefragten Textmuster.

Eine solche Abfrage befindet sich im folgenden Codeblock. Eine Filterung würde im Normalfall beispielsweise mit dem Textmuster ‘Error:%’ erfolgen. In diesem Beispiel interessieren uns Ereignisse im Zusammenhang mit der Datenbank AdventureWorks2019.

DROP TABLE IF EXISTS #errorLog; -- neue Syntax seit SQL Server 2016

CREATE TABLE #errorLog (LogDate DATETIME, ProcessInfo VARCHAR(64), [Text] VARCHAR(MAX));

INSERT INTO #errorLog
EXEC sp_readerrorlog 0 -- Log Nummer spezifizieren
SELECT *
FROM #errorLog a
WHERE EXISTS (SELECT *
FROM #errorLog b
WHERE [Text] like '%AdventureWorks2019%'
AND a.LogDate = b.LogDate
AND a.ProcessInfo = b.ProcessInfo)
order by LogDate desc

Insgesamt bietet diese Vorgehensweise folgende Vorteile:

  • Die Sortierung kann frei gewählt (ist über den Logfile Viewer auch möglich)
  • Die Auswahl relevanter Filterkriterien ist flexibler und kann bei Bedarf beliebig um and- und or-Kriterien erweitert werden
  • Durch die Verwendung des Self-Join (Join von #errorlog mit #errorlog) über das Datum und die ProzessInfo) werden auch diejenigen Zeilen selektiert, die den Suchtext ‘%AdventureWorks2019%’ nicht enthalten, aber zu dem gleichen Prozess gehören und zum gleichen Zeitpunkt aufgetreten sind wie die AdventureWorks2019 Ereignisse.

Das Ergebnis der o.a. Abfrage nach dem Aushängen und wieder Einhängen der AdventureWorks2019 Datenbank ist in den folgenden Zeilen wiedergegeben (lange Texte in der Textspalte wurden hier jeweils aufgesplittet). Wie man sieht, werden hier nicht nur Ereignisse mit dem Suchtext ‘AdventureWorks2019’ aufgelistet, sondern auch einige mit dem Aus- und Einhängen zusammenhängende Ereignisse, beispielsweise die RemoveStaleDbEntries Zeilen.

Protokoll im Zusammenhang mit dem Aushängen der Datenbank AdventureWorks2019

LogDate ProcessInfo Text
11.06.2024 09:39 spid54 Parallel redo is shutdown for database 'AdventureWorks2019'
with worker pool size [10].
11.06.2024 09:39 spid54 CHECKDB for database 'AdventureWorks2019' finished without
errors on 2024-06-06 09:05:01.280 (local time). This is an informational
message only; no user action is required.
11.06.2024 09:39 spid54 Parallel redo is started for database 'AdventureWorks2019'
with worker pool size [10].
11.06.2024 09:39 spid54 Starting up database 'AdventureWorks2019'.
11.06.2024 09:39 spid54 RemoveStaleDbEntries: Cleanup of stale DB entries called for
database ID: [5]
11.06.2024 09:39 spid54 RemoveStaleDbEntries: Cleanup of stale DB entries skipped
because master db is not memory optimized. DbId: 5.
11.06.2024 09:38 Logon Error: 18456, Severity: 14, State: 38.
11.06.2024 09:38 Logon Login failed for user 'AZUREAD\RainerKlomps'. Reason: Failed to
open the explicitly specified database 'AdventureWorks2019'.
[CLIENT: ]
11.06.2024 09:38 Logon Error: 18456, Severity: 14, State: 38.
11.06.2024 09:38 Logon Login failed for user 'AZUREAD\RainerKlomps'. Reason: Failed to
open the explicitly specified database 'AdventureWorks2019'.
[CLIENT: ]
11.06.2024 09:38 spid83 Setting database option SINGLE_USER to ON for database
'AdventureWorks2019'.

Die vollständige aktuelle Protokolldatei enthielt zu diesem Zeitpunkt 446 Zeilen, während durch das o.a. Statement lediglich 11 Zeilen geliefert wurden.

Fazit

Viele Wege führen nach Rom und viele Möglichkeiten liefern Informationen aus den Log-Dateien. Wählen Sie die bequemere und übersichtliche Variante.

Sie benötigen professionelle Unterstützung oder haben offene Fragen? Unsere Expert:innen helfen Ihnen gerne weiter! Kontaktieren Sie uns gerne einfach über das Kontaktformular

Interesse geweckt?
Vielen Dank! Wir haben Ihre Anfrage erhalten!
Oops! Beim Senden ist etwas schiefgegangen, versuche es erneut.