Analyse-Methodik:
Vom Bauchgefühl zur Diagnose — strukturiert, reproduzierbar, DSGVO-konform
Warum Methodik wichtig ist — oder: "Mein Server ist langsam" ist keine Diagnose
"Mein Server ist langsam." Das ist der Satz, mit dem die meisten Performance-Gespräche beginnen. Nicht "usp_GetKundenUmsatz braucht seit dem letzten Deployment dreimal so lang" oder "PAGEIOLATCH_SH ist um 14 Uhr auf 60% gestiegen." Einfach nur: langsam.
Das ist ein Symptom. Kein Problem. Keine Diagnose. Und wer ohne strukturierte Methodik direkt zu den DMVs springt, wird mit hoher Wahrscheinlichkeit das finden, was er schon immer verdächtigt hat — und nicht die eigentliche Ursache. Der DBA schaut auf Indizes. Der Entwickler schaut auf seinen Code. Der Admin schaut auf die CPU-Last. Jeder optimiert das, was er kennt. Das nennt sich Bestätigungsfehler und ist der häufigste Grund warum Performance-Probleme monatelang bestehen bleiben.
Dieses Kapitel bringt das Phasenmodell, das sich durch die gesamten Kapitel 9 bis 19 wie ein roter Faden zieht, in eine operative Struktur. Es zeigt, wie man von der Nutzerbeschwerde über die strukturierte Datenerhebung zur testbaren Hypothese kommt — und wie man anschließend validiert, ob die Maßnahme wirklich gewirkt hat oder nur die Beschwerde verstummt ist.
Dazu kommt Collect-SqlPerf.ps1 als praktisches Werkzeug für die ersten Phasen, ein Blick auf DSGVO-Aspekte bei der Performance-Analyse und eine Voranschau auf die drei Fallstudien in Kapitel 32, 33 und 34 — an denen das Phasenmodell in der Praxis erprobt wird.
|
Hintergrund: Der Klassiker aus hundert Kundenprojekten |
|---|
|
Das Muster ist immer dasselbe: IT-Leiter ruft an, Server sei seit "zwei Wochen" langsam. Auf die Frage "Seit wann genau?" kommt: "Irgendwann nach dem letzten großen Update." Auf "Welche Queries?" kommt: "Alle. Na ja, vor allem das ERP." Auf "Haben Sie eine Baseline?" kommt Schweigen. |
|
Zwei Stunden später hat man herausgefunden, dass ein Deployment eine skalare Funktion eingeführt hat, die 280.000 Mal pro Query aufgerufen wird. Das hat mit CPU-Last zu tun, mit IO zu tun, mit Statistiken zu tun — aber ohne die Frage "Was hat sich geändert?" hätte man ewig auf PAGEIOLATCH-Werte geschaut. |
Das Phasenmodell: Sechs Schritte von der Beschwerde zur validierten Lösung
Performance-Analyse folgt in der Praxis einem iterativen Zyklus aus sechs Phasen. Iterativ deshalb, weil Phase 4 regelmäßig zurück zu Phase 3 führt — eine Hypothese stellt sich als falsch heraus, man muss neu ansetzen. Das ist keine Niederlage, das ist Wissenschaft. Die Alternative — eine Maßnahme ohne Validierung einzuführen — ist Blindflug mit Adminrechten.
|
Phase |
Name |
Kernfrage |
Werkzeuge |
|---|---|---|---|
|
1 |
Situationsaufnahme |
Was genau ist das Problem? |
Gespräch, Error Log, Monitoring |
|
2 |
Baseline erheben |
Was ist normal auf diesem System? |
Collect-SqlPerf.ps1, DMV-Snapshots |
|
3 |
Top-Down-Analyse |
Wo ist der Engpass? |
Wait Statistics, IO, Memory, CPU |
|
4 |
Hypothese formulieren |
Was ist die wahrscheinlichste Ursache? |
DMVs, Extended Events, Query Store |
|
5 |
Maßnahme und Test |
Behebt diese Maßnahme das Problem? |
Testumgebung, A/B-Messung |
|
6 |
Validierung |
Hat es wirklich geholfen? |
Vorher/Nachher-Messung, Nutzer-Feedback |
Tab. 31.1 – Das sechsphasige Performance-Analyse-Modell

Abb. 31.1: Das iterative Phasenmodell: Situationsaufnahme → Baseline → Analyse → Hypothese → Maßnahme → Validierung
Phase 1: Situationsaufnahme — zehn Fragen die man zuerst stellen muss
Der häufigste Fehler in Phase 1: direkt mit der Diagnose beginnen. Bevor eine einzige DMV aufgerufen wird, müssen zehn Fragen beantwortet sein. Diese Fragen kosten fünf Minuten — und sparen manchmal zwei Stunden Irrweganalyse.
Frage 10 klingt banal, ist aber entscheidend: Bei einer aktiven Produktionskrise geht Stabilisierung vor Diagnose. Erst die Lage beruhigen — durch Neustart eines Prozesses, Abbruch einer blockierenden Session, temporäres Rollback — und dann die Ursache untersuchen. Kapitel 14 (Blocking und Deadlocks) beschreibt genau dieses Triage-Muster.
-- Phase 1: Erste Orientierung — Was passiert gerade?
-- Aktive Sessions, Wait Types, Blocking auf einen Blick
SELECT
r.session_id,
r.status, -- RUNNING, RUNNABLE, SLEEPING, SUSPENDED
r.wait_type, -- Das ist die erste Diagnose-Information
r.wait_time / 1000.0 AS WarteSekunden,
r.blocking_session_id, -- > 0 bedeutet: jemand blockiert diese Session
r.cpu_time / 1000.0 AS CPUSekunden,
r.logical_reads AS LogischeLeseop,
r.total_elapsed_time / 1000.0 AS GesamtdauerSek,
SUBSTRING(t.text, 1, 300) AS AktuelleAbfrage
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.session_id <> @@SPID -- eigene Diagnose-Session nicht anzeigen
ORDER BY r.wait_time DESC; -- die am längsten wartenden Sessions oben
Wenn du blocking_session_id > 0 siehst und sich das über mehrere Sessions aufbaut: Das ist ein Blocking-Baum. Sofortmaßnahme vor aller weiteren Diagnose: die blockierende Root-Session identifizieren und entscheiden ob sie abgebrochen werden muss. Alles andere wartet.
Phase 2: Baseline erheben — ohne Referenzwert ist alles Spekulation
Kapitel 9 hat Baseline-Erhebung als eigenständiges Konzept eingeführt. Hier die operative Seite: Was erhebst du, wann, und wie interpretierst du es?
Für neue Server ohne Baseline: Collect-SqlPerf.ps1 mindestens zweimal ausführen — einmal in einer ruhigen Phase, einmal in der Lastspitze. Diese zwei Snapshots sind die Anfangs-Baseline. In der dritten Woche: Trendanalyse. Ohne diesen Referenzwert ist jede Aussage über "auffällig" eine Meinung, keine Diagnose.
-- Baseline-Snapshot: Wait Statistics + IO + Memory in einem Durchlauf
-- Diese Query in ruhiger Phase UND in der Lastspitze ausführen
-- Schritt 1: Wait Statistics — Hauptindikator für Engpass-Typ
SELECT TOP 15
GETDATE() AS Zeitstempel,
wait_type,
wait_time_ms,
waiting_tasks_count,
-- Prozentualer Anteil: das Wichtigste in der Wait Statistics Analyse
100.0 * wait_time_ms / NULLIF(SUM(wait_time_ms) OVER (), 0) AS AnteilProzent
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
-- Idle-Waits herausfiltern — sie verzerrten das Bild massiv
'SLEEP_TASK', 'WAITFOR', 'BROKER_TO_FLUSH', 'BROKER_TASK_STOP',
'CLR_AUTO_EVENT', 'DISPATCHER_QUEUE_DEMAND', 'FT_IFTS_SCHEDULER_IDLE_WAIT',
'HADR_WORK_QUEUE', 'SQLTRACE_BUFFER_FLUSH', 'LOGMGR_QUEUE',
'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',
'BROKER_EVENTHANDLER', 'ONDEMAND_TASK_QUEUE', 'XE_DISPATCHER_WAIT',
'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', 'SNI_HTTP_ACCEPT')
ORDER BY wait_time_ms DESC;
-- Schritt 2: IO-Latenzen pro Datenbankdatei
SELECT
DB_NAME(vfs.database_id) AS Datenbank,
mf.physical_name AS Dateiname,
vfs.io_stall_read_ms / NULLIF(vfs.num_of_reads, 0) AS AvgReadLatenzMs,
vfs.io_stall_write_ms / NULLIF(vfs.num_of_writes, 0) AS AvgWriteLatenzMs,
vfs.num_of_reads,
vfs.num_of_writes
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
JOIN sys.master_files mf
ON vfs.database_id = mf.database_id
AND vfs.file_id = mf.file_id
ORDER BY (vfs.io_stall_read_ms + vfs.io_stall_write_ms) DESC;
-- Schritt 3: Memory — Page Life Expectancy und Buffer Cache Hit
SELECT object_name, counter_name, cntr_value
FROM sys.dm_os_performance_counters
WHERE counter_name IN (
'Page life expectancy',
'Buffer cache hit ratio',
'Memory Grants Pending',
'Target Server Memory (KB)',
'Total Server Memory (KB)')
ORDER BY counter_name;
|
Tipp: Baseline-Zeitpunkte: Wann ist der beste Zeitpunkt? |
|---|
|
Lastspitze (typisch morgens 9–11 Uhr oder nach einem Batch-Lauf): Das ist die "Worst-Case-Baseline". Alles was darüber liegt, ist auffällig. |
|
Ruhephase (nachts oder am Wochenende): Die "Minimum-Baseline". Zeigt den Grundverbrauch ohne Nutzer-Last. |
|
Nach Änderungen: Nach jedem Deployment oder jeder Konfigurationsänderung — damit du sofort siehst ob sich etwas verschlechtert hat. |
|
Wöchentlich zur selben Zeit: Trendanalyse. Langsame Verschlechterungen über Wochen erkennt man nur mit regelmäßigen Vergleichs-Snapshots. |
Was ist ein "normaler" Wert ohne eigene Baseline? Richtwerte aus Kapitel 9 zur Orientierung: PLE über 4.000 Sekunden für normale OLTP-Systeme. IO Read-Latenz unter 5 ms (SSD/NVMe), unter 20 ms (Spindel). CPU Signal Wait unter 25% der Gesamtwartezeit. Diese Werte sind Anhaltspunkte, keine Absoluta — manche Systeme laufen gesund mit PLE von 800, andere haben Performance-Probleme bei PLE von 10.000.
Phase 3: Top-Down-Analyse — der Engpass bekommt einen Namen
Top-Down-Analyse bedeutet: vom Allgemeinen zum Speziellen. Zuerst Wait Statistics — die sagen dir, welche Ressource fehlt. Dann die betroffene Ressource im Detail. Dann die konkreten Abfragen. Nicht umgekehrt. Wer mit der schlechtesten Query beginnt, ohne zu wissen, ob das überhaupt das Problem ist, optimiert womöglich etwas, das null Auswirkung auf die Nutzer hat.
Der Top-Down-Ansatz in sechs Schritten:
-- Phase 3, Schritt 6: Top-Queries nach CPU-Verbrauch (kumulativ)
-- Erst nach den Wait Statistics ausführen — damit klar ist, ob CPU überhaupt das Problem ist
SELECT TOP 20
qs.execution_count,
-- CPU pro Ausführung in Millisekunden:
qs.total_worker_time / 1000 / qs.execution_count AS AvgCPUms,
qs.total_elapsed_time / 1000 / qs.execution_count AS AvgDauerms,
qs.total_logical_reads / qs.execution_count AS AvgLogReads,
qs.total_physical_reads / qs.execution_count AS AvgPhysReads,
-- Gesamtverbrauch: Häufigkeit mal Kosten — das wahre Bild
qs.total_worker_time / 1000 AS GesamtCPUms,
DB_NAME(st.dbid) AS Datenbank,
OBJECT_NAME(st.objectid, st.dbid) AS Prozedur,
SUBSTRING(st.text, 1, 200) AS QueryText
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
WHERE qs.execution_count > 5 -- selten laufende Queries ignorieren
ORDER BY qs.total_worker_time DESC;
Wichtig: GesamtCPUms ist oft aufschlussreicher als AvgCPUms. Eine Query, die 5 ms kostet, aber 500.000 Mal pro Stunde läuft, verursacht mehr CPU als eine, die 10 Sekunden dauert, aber nur zweimal täglich. Kapitel 15 behandelt die Analyse von Ausführungsplänen für genau diese Fälle — inklusive wie man den Unterschied zwischen einem einzelnen teuren Plan und einem häufig aufgerufenen günstigen Plan erkennt.
Der Top-Down-Ansatz verhindert die "Überoptimierung an der falschen Stelle". Wenn der dominante Wait Type ASYNC_NETWORK_IO ist — die Applikation wartet auf das Netzwerk — hilft kein Index der Welt. Dann ist es ein Applikationsproblem (Kap. 25, Kap. 30). Wer zuerst Wait Statistics schaut, wählt seinen Diagnose-Pfad mit System.
Phase 4: Hypothese formulieren — messbar und falsifizierbar
Eine Hypothese ist keine Vermutung. Sie ist eine testbare Aussage: "Wenn ich Index X anlege, sinken die PAGEIOLATCH_SH-Waits um mindestens 40% und die Durchschnittslatenz von usp_GetBestellung sinkt von 850 ms auf unter 200 ms." Das ist messbar. Das ist falsifizierbar. Das ist eine Hypothese.
"Der Server braucht mehr RAM" ist keine Hypothese. "Max Server Memory auf 56 GB anheben erhöht den PLE von 1.200 auf über 3.000 und senkt PAGEIOLATCH_SH von 35% auf unter 10%" — das ist eine Hypothese.
Die Qualität einer Hypothese bestimmt die Qualität der Analyse. Eine vage Hypothese führt zu einer vagen Maßnahme die man nachher nicht validieren kann. Dann ist der Server "irgendwie besser" — oder auch nicht, aber die Beschwerden haben aufgehört. Beides ist keine Diagnose.
|
Warnung: Niemals mehrere Maßnahmen gleichzeitig |
|---|
|
Die häufigste Validation-Falle: Man legt drei Indizes an, aktiviert RCSI, erhöht Max Server Memory, und startet den Server neu — alles in einer Nacht. Am nächsten Tag ist es besser. Was hat geholfen? |
|
Niemand weiß es. Das nächste Mal, wenn das Problem wiederkehrt, weiß man immer noch nicht warum es damals geholfen hat. |
|
Die Regel: Eine Maßnahme pro Validierungs-Zyklus. In einer Produktionskrise bricht man diese Regel — aber bewusst, und man dokumentiert es. |
Extended Events spielen in Phase 4 ihre stärkste Rolle: gezielt für die identifizierte Problemklasse. Nicht eine "alles erfassen"-Session, sondern ein präzises Event, das die Hypothese bestätigt oder widerlegt. Kapitel 8 zeigt, wie man XE-Sessions konfiguriert. Hier ein typisches Beispiel für die Phase-4-Diagnose bei Parameter Sniffing:
-- Phase 4: Gezielte Diagnose mit Extended Events
-- Nur für die Hypothesen-Überprüfung aktivieren — danach sofort stoppen
-- Szenario: Hypothese 'usp_GetBestellung hat einen schlechten Plan durch Parameter Sniffing'
CREATE EVENT SESSION [ParamSniffDiagnose] ON SERVER
ADD EVENT sqlserver.sql_statement_completed(
ACTION(
sqlserver.sql_text,
sqlserver.plan_handle,
sqlserver.database_name
)
WHERE sqlserver.like_i_sql_unicode_string(N'%usp_GetBestellung%')
AND duration > 500000 -- nur Ausführungen über 500 ms erfassen
),
ADD TARGET package0.ring_buffer(SET max_memory = 20480) -- 20 MB reichen
WITH (
MAX_DISPATCH_LATENCY = 10 SECONDS,
TRACK_CAUSALITY = OFF -- Overhead minimieren
);
-- Session starten:
ALTER EVENT SESSION [ParamSniffDiagnose] ON SERVER STATE = START;
-- Nach der Diagnose: SOFORT wieder aufräumen
ALTER EVENT SESSION [ParamSniffDiagnose] ON SERVER STATE = STOP;
DROP EVENT SESSION [ParamSniffDiagnose] ON SERVER;
Phase 5: Maßnahme testen — erst in der Testumgebung, dann in Produktion
Die goldene Regel: Keine Maßnahme geht ungetestet in Produktion. Das klingt selbstverständlich und wird erschreckend oft ignoriert — weil "wir haben keine Testumgebung" oder "es ist dringend". Beides sind schlechte Ausreden.
Wenn es keine Testumgebung gibt: Die kleinste akzeptable Alternative ist ein Maintenance-Window mit Rollback-Plan. Nicht schön, aber ehrlich. Was man nie machen sollte: eine Konfigurationsänderung oder einen Index in der Stoßzeit ohne jede Vorbereitung einführen.
Phase 6: Validierung — hat die Maßnahme wirklich gewirkt?
Validierung ist nicht "der Nutzer hat aufgehört zu klagen." Nutzer gewöhnen sich an langsame Systeme und klagen irgendwann nicht mehr — das ist kein Erfolg, das ist Resignation. Echte Validierung ist quantitativ.
-- Vorher/Nachher-Vergleich: Wait Statistics Delta
-- Snapshot VOR der Maßnahme in Temp-Tabelle speichern
SELECT wait_type, wait_time_ms, waiting_tasks_count
INTO #WaitVorher
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN ('SLEEP_TASK', 'WAITFOR', 'LOGMGR_QUEUE', 'CHECKPOINT_QUEUE');
-- Maßnahme durchführen...
-- Warten bis ausreichend Last gelaufen ist (mindestens 30 Minuten)
-- Nachher-Vergleich: Delta berechnen
SELECT
n.wait_type,
n.wait_time_ms - v.wait_time_ms AS DeltaWaiteMS,
n.waiting_tasks_count - v.waiting_tasks_count AS DeltaTasks,
-- Anteil des Deltas am Gesamt-Delta:
100.0 * (n.wait_time_ms - v.wait_time_ms)
/ NULLIF(SUM(n.wait_time_ms - v.wait_time_ms) OVER (), 0) AS AnteilProzent
FROM sys.dm_os_wait_stats n
JOIN #WaitVorher v ON n.wait_type = v.wait_type
WHERE n.wait_time_ms > v.wait_time_ms -- nur Waits die zugenommen haben
ORDER BY DeltaWaiteMS DESC;
DROP TABLE #WaitVorher;
-- Query Store: Automatischer Vorher/Nachher-Vergleich (SQL Server 2016+)
-- Kap. 19 erklärt Query Store im Detail — hier der schnelle Vergleich:
SELECT TOP 20
q.query_id,
OBJECT_NAME(q.object_id) AS Prozedur,
rs.avg_duration / 1000.0 AS AvgDauerMS,
rs.avg_cpu_time / 1000.0 AS AvgCPUms,
rs.avg_logical_io_reads AS AvgLogReads,
rs.count_executions AS Ausfuehrungen,
rs.first_execution_time,
rs.last_execution_time
FROM sys.query_store_query q
JOIN sys.query_store_plan p ON q.query_id = p.query_id
JOIN sys.query_store_runtime_stats rs ON p.plan_id = rs.plan_id
ORDER BY rs.avg_duration DESC;
Query Store (Kapitel 19) ist der natürliche Partner für Phase 6: Er speichert Ausführungsstatistiken mit Zeitstempel und ermöglicht einen direkten Vergleich von "vor" und "nach" für jede Query — ohne manuelles Snapshot-Verwalten. Wenn Query Store aktiviert ist, ist es das erste Werkzeug für die Validierung.
Collect-SqlPerf.ps1 — strukturierte Datenerhebung für Phase 1 bis 3
Collect-SqlPerf.ps1 ist ein PowerShell-Script, das die Datenerhebung für die ersten drei Phasen des Analyse-Modells in einem Durchlauf automatisiert. Es sammelt alle relevanten DMV-Daten, speichert sie reproduzierbar mit Zeitstempel und liefert strukturiert erfasste Rohdaten als Grundlage für die Analyse — die eigentliche Diagnose leistet das Handwerkszeug aus den Kapiteln 8 bis 19 dieses Buchs.
Das Script ist unter boddenberg.de verfügbar und wird dort gepflegt. Anhang F enthält Bezugsquelle und Installationshinweise. Der typische Ablauf bei einem Kundeneinsatz: Als erstes das Script ausführen, die erhobenen Daten sichern, und dann mit den Methoden aus den Kapiteln 8 bis 19 in die Analyse einsteigen. Das ist effizienter als zwei Stunden DMV-Abklopfen ohne Plan.
Was Collect-SqlPerf.ps1 erhebt
|
Bereich |
DMV / Quelle |
Was du bekommst |
|---|---|---|
|
Wait Statistics |
sys.dm_os_wait_stats |
Top-15 Wait Types mit Prozentanteil |
|
Top Queries CPU |
sys.dm_exec_query_stats |
Top-20 CPU-intensive Abfragen |
|
Top Queries IO |
sys.dm_exec_query_stats |
Top-20 IO-intensive Abfragen |
|
IO-Latenzen |
sys.dm_io_virtual_file_stats |
Latenz pro Datenbankdatei (Read + Write) |
|
Memory / PLE |
sys.dm_os_performance_counters |
Page Life Expectancy, Buffer Cache Hit Ratio |
|
Memory Grants |
sys.dm_exec_query_memory_grants |
Ausstehende und gewährte Memory Grants |
|
TempDB |
sys.dm_db_file_space_usage |
Version Store, interne Objekte, Dateiaufteilung |
|
Blocking |
sys.dm_exec_requests |
Aktive Blocking-Ketten mit Session-Details |
|
Index-Nutzung |
sys.dm_db_index_usage_stats |
Seeks vs. Scans, unbenutzte Indizes |
|
Fehlende Indizes |
sys.dm_db_missing_index_details |
SQL Servers Empfehlungen mit Verbesserungspotenzial |
|
Autogrowth |
sys.fn_trace_gettable |
Wachstumsereignisse der letzten 24 Stunden |
|
Konfiguration |
sys.configurations |
Alle sp_configure-Werte im Vergleich zu Empfehlungen |
Tab. 31.2 – Was Collect-SqlPerf.ps1 erfasst
|
Hinweis: Professionelle SQL Server Analyse als Dienstleistung |
|---|
|
Wer die Datenerhebung und Analyse lieber in erfahrene Hände geben möchte: Ulrich B. Boddenberg bietet strukturierte SQL Server Performance-Analysen zum Festpreis an — mit vollständigem Befundbericht und priorisierten Handlungsempfehlungen. |
|
Weitere Informationen: https://www.boddenberg.de/sql-server-performance-analyse/ |
Typische Verwendung
# Collect-SqlPerf.ps1 — Grundlegende Verwendung
# Voraussetzung: PowerShell 5.1+, SqlServer-Modul, Lesezugriff auf alle DMVs
# Standard-Durchlauf: alle Metriken, ohne Query-Texte (DSGVO-konform)
.\Collect-SqlPerf.ps1 -ServerInstance "MWSQL01" -Database "master"
# Mit Ausgabepfad und eigenem Prefix für die Dateibenennung:
.\Collect-SqlPerf.ps1 `
-ServerInstance "MWSQL01" `
-OutputPath "C:\Analyse\2024-03-15" `
-Prefix "Musterwerk_Lastspitze"
# Mit Query-Text-Erfassung — nur nach explizitem DSGVO-Opt-in!
.\Collect-SqlPerf.ps1 `
-ServerInstance "MWSQL01" `
-IncludeQueryText ` # Query-Texte erfassen
-IncludeLoginNames # Login-Namen erfassen
# Zwei Snapshots vergleichen (Vorher/Nachher-Analyse):
.\Compare-SqlPerf.ps1 `
-Baseline "C:\Analyse\Vorher\*.json" `
-Current "C:\Analyse\Nachher\*.json" `
-OutputPath "C:\Analyse\Vergleich"
# Ergebnis: HTML-Report + CSV-Dateien für Trendanalyse in Excel
Kernlogik: DMV-Erhebung in PowerShell
# Ausschnitt aus Collect-SqlPerf.ps1 — Kern-Erhebungslogik
# Zeigt das Prinzip: strukturiertes Abfragen und Speichern der DMVs
param(
[string]$ServerInstance = "localhost",
[string]$Database = "master",
[string]$OutputPath = ".\SqlPerfOutput",
[string]$Prefix = "SqlPerf",
[switch]$IncludeQueryText, # Opt-in: DSGVO-relevant!
[switch]$IncludeLoginNames # Opt-in: DSGVO-relevant!
)
# Ausgabeverzeichnis erstellen falls nicht vorhanden
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$outDir = Join-Path $OutputPath "${Prefix}_${timestamp}"
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
# Hilfsfunktion: SQL-Abfrage ausführen und als JSON speichern
function Invoke-SqlAndSave {
param([string]$Query, [string]$FileName)
$result = Invoke-Sqlcmd -ServerInstance $ServerInstance `
-Database $Database `
-Query $Query `
-TrustServerCertificate
$result | ConvertTo-Json -Depth 3 |
Out-File (Join-Path $outDir "$FileName.json") -Encoding UTF8
Write-Host " OK: $FileName ($($result.Count) Zeilen)"
}
# Wait Statistics erheben:
Invoke-SqlAndSave -FileName "wait_stats" -Query @"
SELECT TOP 20 wait_type, wait_time_ms, waiting_tasks_count,
100.0 * wait_time_ms / NULLIF(SUM(wait_time_ms) OVER (), 0) AS AnteilProzent
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN ('SLEEP_TASK','WAITFOR','LOGMGR_QUEUE','CHECKPOINT_QUEUE')
ORDER BY wait_time_ms DESC
"@
# IO-Latenzen erheben:
Invoke-SqlAndSave -FileName "io_latency" -Query @"
SELECT DB_NAME(database_id) AS DB,
io_stall_read_ms / NULLIF(num_of_reads, 0) AS AvgReadMS,
io_stall_write_ms / NULLIF(num_of_writes, 0) AS AvgWriteMS
FROM sys.dm_io_virtual_file_stats(NULL, NULL)
"@
# Query-Texte NUR mit explizitem Opt-in erfassen
if ($IncludeQueryText) {
Write-Warning "Query-Texte werden erfasst — DSGVO-Opt-in erforderlich!"
Invoke-SqlAndSave -FileName "top_queries_text" -Query @"
SELECT TOP 20 total_worker_time / execution_count AS AvgCPU,
SUBSTRING(st.text, 1, 500) AS QueryText
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY total_worker_time DESC
"@
}
Write-Host "Collect-SqlPerf.ps1 abgeschlossen: $outDir"
Das Script erzeugt am Ende eine strukturierte Ausgabe: JSON-Dateien pro Bereich und eine HTML-Übersichtsseite mit den rohen Messwerten. Diese Rohdaten sind der Startpunkt für die Analyse — kein Selbstläufer, aber eine vollständige Datengrundlage. Schlägt die Wait Statistics hohe PAGEIOLATCH_SH aus? Dann geht es mit Kapitel 10 weiter. Zeigt die PLE einen Abfall unter 1.000 Sekunden? Dann ist Kapitel 11 der nächste Halt.
Typische Script-Ausgabe und Interpretation
# Beispielausgabe (vereinfacht):
# === Collect-SqlPerf.ps1 === 2024-03-15 14:32:18
# Server: MWSQL01 | SQL Version: 2019 (15.0.4312) | Cores: 8 | RAM: 64 GB
# [WAIT STATISTICS] Top 5 Wait Types:
# 1. PAGEIOLATCH_SH 41.2% → IO-Engpass, Lesen aus Storage
# 2. LCK_M_S 18.7% → Blocking durch Shared Locks
# 3. SOS_SCHEDULER_YIELD 9.1% → CPU-Sättigung / Scheduler-Druck
# 4. CXPACKET 7.3% → Parallelismus (prüfen ob Signal Wait hoch)
# 5. RESOURCE_SEMAPHORE 5.8% → Memory Grant Wartezeiten
# [IO LATENCY] Datenbankdateien:
# MeineDB.mdf Read: 4.2 ms avg Write: 2.1 ms avg → OK (SSD-typisch)
# MeineDB.ldf Read: 1.1 ms avg Write: 28.7 ms avg → Log-Write-Latenz hoch!
# tempdb.mdf Read: 3.1 ms avg Write: 3.4 ms avg → OK
# [MEMORY] PLE: 3.847 Sekunden (Richtwert OLTP: > 4.000) → leicht unter Normal
# Buffer Cache Hit Ratio: 99.2% → gut
# [TOP QUERIES CPU]:
# 1. Proc: usp_GetKundenUmsatz CPU avg: 847 ms Executions: 4.200/h
# 2. Proc: usp_MonatsReport CPU avg: 12.400 ms Executions: 2/h
# [EMPFEHLUNG] Schwerpunkt: Log-Schreib-Latenz + PAGEIOLATCH_SH
# → Kap. 10 (IO-Performance), Kap. 2 (Storage Deep Dive)
Die erhobenen Daten sind kein Selbstläufer — sie zeigen, wo zu schauen ist, nicht was zu tun ist. Aber sie ersetzen das stundenlange manuelle DMV-Abklopfen durch einen strukturierten Startpunkt und schaffen eine gemeinsame Datenbasis für das Gespräch mit dem Kunden.
DSGVO und Performance-Analyse: Was erlaubt ist, was nicht
Performance-Analyse auf Produktionssystemen greift auf technische Metadaten zu. Das ist grundsätzlich unproblematisch. Kritisch wird es an genau einer Stelle: wenn personenbezogene Daten in den erfassten Daten enthalten sind.
Was unkritisch ist
Wait Types, IO-Latenzen, CPU-Auslastung, PLE, Execution Counts, Query-Hashes (ohne Text), Ausführungspläne ohne Parameterwerte — all das sind rein technische Metadaten. Kein Personenbezug, keine DSGVO-Relevanz. Collect-SqlPerf.ps1 erfasst in der Standardkonfiguration ausschließlich diese unkritischen Daten.
Was DSGVO-relevant ist
|
Hinweis: DSGVO-konforme Performance-Analyse: Checkliste |
|---|
|
1. Vor der Analyse: Mit IT-Sicherheit und ggf. Betriebsrat abstimmen, welche Daten erfasst werden dürfen. |
|
2. Collect-SqlPerf.ps1 ohne -IncludeQueryText und -IncludeLoginNames ausführen (Standard). |
|
3. Wenn Query-Texte nötig sind: schriftliche Genehmigung einholen, Analyse-Daten nach Abschluss löschen. |
|
4. Extended Events: sql_text-Action nur aktivieren, wenn unbedingt nötig, Session sofort nach Diagnose löschen. |
|
5. Analyse-Ergebnisse nicht dauerhaft auf Berater-Laptops speichern — oder mit definierter Löschfrist. |
|
6. Bei externen Consultants: Datenschutzkonzept und Auftragsverarbeitungsvertrag vorab klären. |
|
Warnung: Query Store und persistente Query-Texte |
|---|
|
Query Store (Kap. 19) speichert Query-Texte persistent in der Datenbank — das ist sein Kernfeature. Das bedeutet: Wer Zugriff auf sys.query_store_query_text hat, kann Query-Texte lesen. |
|
In hochsensiblen Umgebungen: Zugriff auf sys.query_store_query_text auf db_owner oder eine spezifische DBA-Rolle beschränken. Normale Entwickler sollten diesen View nicht ohne weiteres abfragen können. |
|
Query Store Retention prüfen: Wie lange werden Query-Texte gespeichert? Standard ist 30 Tage. In manchen Umgebungen muss das kürzer sein. |
Extended Events: Welche Session für welches Problem?
Kapitel 8 behandelt Extended Events vollständig — Session-Design, Target-Typen, Ring Buffer vs. File Target, Overhead-Abschätzung. Hier der operative Überblick: Welche XE-Session für welches Problem in der Diagnose-Phase 4?
|
Problem |
XE-Event |
Key Action |
Sinnvolle Schwelle |
|---|---|---|---|
|
Langsame Queries |
sql_statement_completed |
sql_text, plan_handle |
duration > 1.000.000 µs (= 1 s) |
|
Deadlocks |
xml_deadlock_report |
keine nötig |
alle Deadlocks — System Health hat sie bereits |
|
Blocking |
blocked_process_report |
sql_text |
blocked_process_threshold > 5 s konfigurieren |
|
Memory Pressure |
memory_broker_shrink_notification |
keine nötig |
alle Ereignisse |
|
Autogrowth |
database_file_size_change |
database_name |
Wachstum > 0 |
|
Parameter Sniffing |
sql_statement_recompile |
sql_text, recompile_cause |
alle Recompilations |
|
Kompilierungsrate |
sql_statement_starting |
sql_text |
Frequenz > 100/s verdächtig |
Tab. 31.3 – XE-Sessions für häufige Performance-Probleme in Phase 4
Die System Health Session läuft immer und enthält Deadlock-Graphen, schwere Fehler, Memory-Druckereignisse und langlaufende Queries — standardmäßig aktiv, minimaler Overhead, keine Konfiguration nötig. Immer dort nachschauen, bevor eine eigene Session gestartet wird.
-- System Health Session: Deadlock-Graphen der letzten Stunden auslesen
-- Kein Setup nötig — läuft auf jeder SQL Server Instanz (2008+)
SELECT
xdr.value('(event/@timestamp)[1]', 'datetime2') AS Zeitstempel,
xdr.query('.') AS DeadlockGraph
FROM (
SELECT CAST(target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets t
JOIN sys.dm_xe_sessions s ON t.event_session_address = s.address
WHERE s.name = N'system_health'
AND t.target_name = N'ring_buffer'
) AS Data
CROSS APPLY TargetData.nodes('//RingBufferTarget/event[@name="xml_deadlock_report"]')
AS XEventData(xdr)
ORDER BY Zeitstempel DESC;
-- Ergebnis: XML-Deadlock-Graph — in SSMS auf den Link klicken für grafische Ansicht
Der Analyse-Bericht: Struktur und Inhalt
Ein Performance-Analyse-Bericht ist kein Monitoring-Dashboard. Er ist ein strukturiertes Dokument, das Befunde erklärt, priorisiert und mit konkreten Maßnahmen verbindet. Der Unterschied zwischen einem Report, den der IT-Leiter liest, und einem, den er in der Schublade vergräbt: Priorisierung und klare Handlungsempfehlung.
|
Abschnitt |
Inhalt |
Länge |
Zielgruppe |
|---|---|---|---|
|
Executive Summary |
Top-3 Probleme, Risikobewertung, Priorisierung |
1 Seite |
IT-Leitung, Management |
|
Systemübersicht |
SQL Server Version, Hardware, Konfiguration |
1–2 Seiten |
DBA-Team |
|
Befunde |
Jeder Befund einzeln: Messwert, Auswirkung, Ursache |
3–8 Seiten |
DBA-Team, Entwickler |
|
Maßnahmenplan |
Priorisierte Maßnahmen: wer, was, bis wann, wie validiert |
1–2 Seiten |
Alle |
|
Anhang |
Ausführungsplan-Screenshots, DMV-Rohdaten, XE-Ergebnisse |
variabel |
DBA-Team |
Tab. 31.4 – Struktur eines Performance-Analyse-Berichts
Priorisierung: Impact mal Aufwand
Nicht jede Maßnahme ist gleich wertvoll. Die Impact-Aufwand-Matrix ist das einfachste und effektivste Priorisierungswerkzeug — und sie spart Kundengespräche, weil sie Erwartungen sofort kalibriert.
|
Kategorie |
Beispiele |
Typischer Aufwand |
Erwarteter Impact |
|---|---|---|---|
|
Quick Win |
Max Server Memory setzen, RCSI aktivieren, sp_configure-Fehler korrigieren |
< 1 Stunde |
Hoch, sofort messbar |
|
Kurzfristig |
Fehlende Indizes anlegen, Statistiken aktualisieren, TempDB konfigurieren |
1–4 Stunden |
Hoch bis mittel |
|
Mittelfristig |
Stored Procedures refactoren, Wartungs-Jobs einrichten, Query Store aktivieren |
1–3 Tage |
Mittel, nachhaltig |
|
Langfristig |
Applikations-Refactoring, ORM-Optimierung, Hardware-Upgrade |
Wochen bis Monate |
Hoch, aber mit Vorlaufzeit |
Tab. 31.5 – Impact-Aufwand-Matrix für Performance-Maßnahmen
Quick Wins zuerst — nicht, weil sie die wichtigsten sind, sondern, weil sie Vertrauen schaffen. Wenn Max Server Memory nach zehn Minuten Arbeit den PLE verdoppelt, ist der Kunde bereit für das Gespräch über das dreiwöchige Applikations-Refactoring. Ohne diesen Quick Win ist das Gespräch schwieriger.
Checkliste: Die ersten 30 Minuten bei einem unbekannten Server
Du wirst zu einem Server gerufen, den du nie gesehen hast. "Es ist langsam." Was machst du? Die folgende Checkliste gibt dir in 30 Minuten einen vollständigen Überblick — ohne Vorwissen über das System.
|
Minute |
Aktion |
Werkzeug |
Ziel |
|---|---|---|---|
|
0–2 |
Versionsinformation, Hardware, Uptime |
SELECT @@VERSION, sys.dm_os_sys_info |
Kontext verstehen |
|
2–5 |
Aktive Sessions und Blocking |
sys.dm_exec_requests |
Akutes Problem erkennen |
|
5–10 |
Wait Statistics (letzte 5 Min) |
sys.dm_os_wait_stats |
Engpass-Typ identifizieren |
|
10–15 |
IO-Latenzen Datenbankdateien |
sys.dm_io_virtual_file_stats |
IO-Problem lokalisieren |
|
15–20 |
Memory: PLE, Buffer Cache Hit |
sys.dm_os_performance_counters |
Memory-Druck prüfen |
|
20–25 |
Top Queries CPU + IO |
sys.dm_exec_query_stats |
Hauptverdächtigen benennen |
|
25–30 |
Konfiguration: sp_configure |
sys.configurations |
Offensichtliche Fehlconfig? |
Tab. 31.6 – Erste-30-Minuten-Checkliste für den unbekannten Server
Nach 30 Minuten solltest du eine Hypothese haben. Nicht zwingend die Antwort — aber eine Richtung. "Der dominante Wait Type ist PAGEIOLATCH_SH, die IO-Latenz auf der Log-Datei liegt bei 28 ms — das ist der erste Befund." Das ist eine Hypothese, die dich in Phase 4 führt.
-- Die ersten 3 Minuten: Systemkontext herstellen
SELECT @@VERSION;
SELECT
cpu_count AS LogischeCPUs,
hyperthread_ratio AS HyperthreadRatio,
physical_memory_kb / 1024 AS PhysRAM_MB,
sqlserver_start_time AS SQLStartzeit,
-- Uptime in Stunden:
DATEDIFF(HOUR, sqlserver_start_time, GETDATE()) AS UptimeStunden
FROM sys.dm_os_sys_info;
-- Wichtige Konfiguration: die häufigsten Fehlkonfigurationen prüfen
SELECT name, value_in_use, description
FROM sys.configurations
WHERE name IN (
'max server memory (MB)',
'min server memory (MB)',
'max degree of parallelism',
'cost threshold for parallelism',
'priority boost', -- sollte 0 sein — Kap. 5 erklärt warum
'lightweight pooling', -- sollte 0 sein
'optimize for ad hoc workloads'
)
ORDER BY name;
-- priority boost = 1? Das ist der erste Quick-Win: auf 0 setzen
-- max server memory unrealistisch? Das ist Quick-Win Nr. 2
|
Praxisbeispiel: Musterwerk GmbH: Erste 30 Minuten auf MWSQL01 |
|---|
|
Beim ersten Besuch: Collect-SqlPerf.ps1 läuft in 4 Minuten durch. Ergebnis: PAGEIOLATCH_SH 38%, LCK_M_S 22%, PLE 3.200 (unter der üblichen Instanz-Richtwert von 4.000). IO-Latenz auf der Datenbankdatei: 6 ms Read, 4 ms Write — vertretbar. |
|
Hypothese: Reader/Writer-Blocking als primäres Problem, Memory leicht unter Druck. Keine IO-Katastrophe. Phase 4: Blocking-Analyse — welche Queries erzeugen LCK_M_S? Kapitel 32 zeigt den vollständigen Analyse-Verlauf für Musterwerk — mit Befund und Maßnahmenplan. |
Typische Analyse-Fehler — und wie man sie vermeidet
Die häufigsten Fehler in Performance-Analysen sind keine technischen Fehler. Es sind methodische Fehler. Die Technik stimmt, die Methodik nicht.
Fehler 1: Die langsamste Query optimieren
"Die langsamste Query ist unser Hauptproblem." Das ist der häufigste Reflex — und oft falsch. Eine Query, die 10 Sekunden dauert, aber zweimal pro Tag läuft, verursacht 20 Sekunden CPU-Last täglich. Eine Query, die 50 ms dauert und 100.000 Mal pro Stunde läuft, verursacht 5.000 Sekunden CPU-Last täglich — Faktor 250 mehr. Wait Statistics und Top-Queries-nach-Gesamtverbrauch zeigen das richtige Bild.
Fehler 2: Reaktiv statt proaktiv
"Wir warten bis es wieder brennt, dann schauen wir nach." Das Problem: wenn es brennt, hat man keine ruhige Minute für eine sorgfältige Analyse. Und ohne Baseline-Snapshot aus der ruhigen Phase weiß man nicht, was "normal" war. Proaktive Baseline-Erhebung und regelmäßiges Monitoring kosten wenig — aber im Krisenmoment sind sie unbezahlbar.
Fehler 3: "Der Server ist schuld"
In etwa 70% aller Performance-Probleme, die ich in Kundenprojekten gesehen habe, war der Ursprung im Code — nicht in der Hardware oder Konfiguration. Trendforge Digital (Kapitel 34) ist das extremste Beispiel: tadellose Hardware, perfekte Konfiguration, katastrophale Applikation. Mehr Hardware hätte das Problem nicht gelöst — es hätte es nur teurer gemacht.
Fehler 4: Keine Testumgebung
"Wir haben keine Testumgebung." Das ist kein Naturgesetz, das ist eine Entscheidung. Und die Konsequenz ist: Produktion wird zur Testumgebung — mit allen Risiken. Wer keine Testumgebung hat und trotzdem Indizes anlegt, sp_configure ändert oder Code deployed, testet in Produktion. Das sollte eine bewusste Entscheidung sein, keine Selbstverständlichkeit.
Fehler 5: "Mehr RAM löst alles"
Hardware-Upgrades sind die teuerste Art, ein Software-Problem zu kaschieren. Sie helfen kurzfristig — aber ohne die eigentliche Ursache zu beheben, wächst das Problem weiter. 64 GB RAM statt 32 GB kauft vielleicht drei Monate Zeit. Danach ist der Buffer Pool wieder voll, der PLE wieder niedrig, und das Hardware-Budget ist weg. Sparfuchs & Partner (Kapitel 33) ist ein gutes Gegenbeispiel: dort war mehr RAM tatsächlich nötig — aber nur als Teil einer umfassenderen Maßnahme, nicht als Allheilmittel.
Vorschau: Das Phasenmodell in der Praxis
Die drei Fallstudien in Kapitel 32, 33 und 34 sind das Phasenmodell in Aktion. Jede Fallstudie zeigt einen anderen Problemtyp — und wie die strukturierte Analyse einen anderen Lösungsweg ergibt.
Kapitel 32: Musterwerk GmbH — der normale Fall
MWSQL01 ist das, was die meisten Admins kennen: solide Hardware, vernünftige Grundkonfiguration, aber über die Jahre gewachsene Probleme. TempDB-Contention, ein Parameter-Sniffing-Problem in der Hauptabfrage, ein fehlender Index der täglich 200.000 Table Scans produziert.
Die Analyse nach dem Phasenmodell führt in drei Stunden zur vollständigen Diagnose. Die Maßnahmen sind überwiegend Konfiguration und Query-Optimierung — kein Hardware-Upgrade nötig. Das ist der typische Verlauf: was wie ein Hardware-Problem aussieht, ist meist ein Konfigurations- oder Code-Problem.
Kapitel 33: Sparfuchs & Partner — der Horror-Fall
BUCHSQL01 ist das, was man sich nicht vorstellen mag aber regelmäßig antrifft: jeder erdenkliche Fehler auf einmal. 4 vCPUs, 8 GB RAM, eine einzige Spindel für OS, TempDB, Datendateien, Log-Dateien und Backup. Max Server Memory auf 8.192 MB bei 8 GB physischem RAM — die Instanz konkurriert mit dem OS um denselben Speicher. IO-Latenz Write p95: 312 ms. Auf NVMe wären das 0,03 ms.
Das Phasenmodell zeigt hier ein komplett überlastetes System bei dem praktisch jede Ressource gleichzeitig gesättigt ist. Die Triage-Entscheidung — was zuerst — ist schwieriger als bei Musterwerk. Die Maßnahmen umfassen Hardware, Konfiguration und Code — ohne eine davon wäre der Erfolg kurzlebig.
Kapitel 34: Trendforge Digital GmbH — der Entwickler-Albtraum
TFSQL01 ist der Ferrari mit Anhängerkupplung: 32 Kerne, 256 GB RAM, NVMe-Storage, SQL Server korrekt konfiguriert. Und trotzdem: Performance-Probleme. Wait Statistics zeigen ASYNC_NETWORK_IO und SOS_SCHEDULER_YIELD — Hinweise auf zu viele kleine Requests und CPU-Last durch Kompilierungen.
Die Phase-4-Analyse enthüllt: N+1-Problem im ORM (2.400 Einzelabfragen statt einem Join), skalare UDF die 180.000 Mal pro Abfrage aufgerufen wird, fehlende WHERE-Klauseln in mehreren aktiven Abfragen. Die Lösung liegt vollständig auf Applikationsebene — der DBA kann das Problem analysieren, aber ohne Entwickler-Kooperation nicht lösen.
Diagnose-Übersicht: Analyse-Methodik
|
Warnung: Symptome: Wann ist strukturierte Methodik dringend nötig? |
|---|
|
Performance-Probleme kehren regelmäßig zurück, obwohl bereits Maßnahmen ergriffen wurden — ein Zeichen, dass die Ursache nie wirklich identifiziert wurde. |
|
Mehrere Maßnahmen wurden gleichzeitig ergriffen und man weiß nicht welche geholfen hat — Validierung fehlt. |
|
Keine Baseline vorhanden: Jede Aussage über "auffällig" ist eine Meinung, keine Diagnose. |
|
Jede Abteilung nennt eine andere Ursache: DBA sagt Index, Entwickler sagt Code, Admin sagt Hardware — klassisches Zeichen für fehlende strukturierte Analyse. |
|
Performance-Analysen enden ohne klare Empfehlung — das ist ein Methodikproblem, kein Technikproblem. |
|
Tipp: So misst du das: Baseline in einem Script |
|---|
|
— Dieses Script liefert die wichtigsten Baseline-Werte in einem Durchlauf. |
|
— Ausführen in ruhiger Phase UND in Lastspitze, Ergebnisse vergleichen. |
|
|
|
PRINT '=== Wait Statistics (Top 10) ==='; |
|
SELECT TOP 10 wait_type, wait_time_ms, |
|
100.0 * wait_time_ms / SUM(wait_time_ms) OVER () AS Anteil |
|
FROM sys.dm_os_wait_stats |
|
WHERE wait_type NOT IN ('SLEEP_TASK','WAITFOR','LOGMGR_QUEUE') |
|
ORDER BY wait_time_ms DESC; |
|
|
|
PRINT '=== IO-Latenzen ==='; |
|
SELECT DB_NAME(database_id) AS DB, |
|
io_stall_read_ms / NULLIF(num_of_reads,0) AS ReadMS, |
|
io_stall_write_ms / NULLIF(num_of_writes,0) AS WriteMS |
|
FROM sys.dm_io_virtual_file_stats(NULL,NULL) |
|
ORDER BY (io_stall_read_ms + io_stall_write_ms) DESC; |
|
|
|
PRINT '=== Memory: PLE und Buffer Cache ==='; |
|
SELECT counter_name, cntr_value |
|
FROM sys.dm_os_performance_counters |
|
WHERE counter_name IN ( |
|
'Page life expectancy','Buffer cache hit ratio', |
|
'Memory Grants Pending'); |
|
Hintergrund: Typische Fehlinterpretationen bei der Methodik |
|---|
|
"Wir wissen was das Problem ist" — Die erstgenannte Ursache ist häufig falsch oder nur eine Schicht des eigentlichen Problems. Strukturierte Analyse erst, dann Hypothese. |
|
"Performance-Analyse dauert Wochen" — Erste belastbare Erkenntnisse sind in 30 Minuten möglich. Die Tiefenanalyse dauert länger, aber der erste Befund kommt schnell. |
|
"DSGVO verhindert Performance-Analyse" — Nein. Technische Metadaten (Wait Types, Latenzen, CPU-Auslastung) sind nicht personenbezogen. Nur Query-Texte und Login-Namen erfordern Opt-in. |
|
"Der Wert ist hoch, also ist er schlecht" — Ohne Baseline kein Vergleich. 85% CPU kann normal sein oder kritisch, je nach System und Tageszeit. |
|
"Wir haben das schon mal gemacht" — Performance-Analyse ist kein einmaliges Projekt. Systeme ändern sich: Datenvolumen wächst, Code ändert sich, Nutzerzahlen steigen. |
|
Tipp: Erste Gegenmaßnahmen: Was sofort hilft |
|---|
|
1. Collect-SqlPerf.ps1 ausführen — strukturierter Überblick in 5 Minuten. |
|
2. Wait Statistics Snapshot nehmen — Was wartet SQL Server gerade auf? |
|
3. Blocking prüfen: sys.dm_exec_requests, blocking_session_id > 0 suchen. |
|
4. Top-10-CPU-Queries identifizieren — sys.dm_exec_query_stats nach total_worker_time sortiert. |
|
5. Error Log lesen — Checkpoint-Verzögerungen, Memory-Pressure-Meldungen, I/O-Fehler? |
|
6. Konfiguration prüfen — priority boost = 1? Max Server Memory zu hoch? Kap. 5 für die Verbotsliste. |
|
Diese sechs Schritte dauern 15 Minuten und liefern in 80% der Fälle eine klare Diagnose-Richtung. |
Zusammenfassung
Performance-Analyse ist kein Bauchgefühl-Sport. Das sechsphasige Modell — Situationsaufnahme, Baseline erheben, Top-Down-Analyse, Hypothese formulieren, Maßnahme testen, Validierung — gibt jedem Analyse-Auftrag eine Struktur, die reproduzierbar, kommunizierbar und verteidigbar ist.
Die zehn Fragen der Situationsaufnahme kosten fünf Minuten und sparen oft Stunden Irrweganalyse. Ohne Baseline ist jede Aussage über "auffällig" eine Meinung. Die Top-Down-Analyse — Wait Statistics zuerst, dann die betroffene Ressource, dann die konkrete Query — verhindert die Überoptimierung an der falschen Stelle.
Collect-SqlPerf.ps1 automatisiert die Datenerhebung der ersten drei Phasen und liefert strukturiert erfasste Rohdaten als Grundlage für die eigentliche Analyse — die dann mit den Methoden aus den Kapiteln 8 bis 19 erfolgt. DSGVO ist kein Hindernis für Performance-Analyse — technische Metadaten sind nicht personenbezogen. Query-Texte und Login-Namen erfordern Opt-in, der Rest nicht.
Die fünf typischen Analyse-Fehler — falsche Query optimieren, reaktiv statt proaktiv vorgehen, Hardware als Allheilmittel, keine Testumgebung, keine Validierung — sind alle methodischer Natur. Das Phasenmodell verhindert sie systematisch.
Extended Events, Query Store und System Health Session sind die Werkzeuge für Phase 4, wenn DMVs nicht reichen. Die System Health Session läuft immer — sie ist der erste Anlaufpunkt für Deadlock-Diagnose, Memory-Ereignisse und langlaufende Queries.
Der Analyse-Bericht endet immer mit einer priorisierten Maßnahmentabelle nach dem Impact-Aufwand-Prinzip: Quick Wins zuerst, damit das Vertrauen wächst und der Spielraum für die tiefgreifenderen Maßnahmen entsteht.
Ausblick auf Kapitel 32: Das Phasenmodell trifft auf die erste Fallstudie — Musterwerk GmbH. Von der Nutzerbeschwerde über den Collect-SqlPerf.ps1-Befund bis zum vollständigen Maßnahmenplan. Der normale Fall — der zeigt, dass normale Probleme mit Bordmitteln lösbar sind, wenn man weiß wie man sucht.

Abb. 2: Eskalationsstufen der Analyse-Methodik
Kapitel 32
