sqmSQLTool · Performance & Diagnose · 2026
Engpässe in Minuten statt Stunden finden — direkt aus PowerShell, ohne externe Tools.
Uwe Janke · Senior SQL Server DBA · dtcSoftware
Warum sqmSQLTool Performance & Diagnose?
Ohne strukturierte Diagnose-Werkzeuge bleibt die Ursachenforschung mühsam und zeitraubend.
Langsame Abfragen existieren — aber niemand weiss, ob sie schon immer so waren oder sich nach einem Change verschlechtert haben.
sys.dm_os_wait_stats liefert Rohdaten. Ohne Normalisierung und Filterung erkennt man Engpässe nicht auf einen Blick.
In vielen Umgebungen ist der Query Store deaktiviert oder nicht konfiguriert — dabei ist er das wirksamste Werkzeug gegen Plan-Regressionen.
DMVs wie sys.dm_db_missing_index_details liefern wertvolle Hinweise, werden aber selten systematisch ausgewertet.
Funktionsüberblick
Alle Funktionen sind in sich geschlossen und können einzeln oder kombiniert in Monitoring-Skripten eingesetzt werden.
Wait-Analyse
Liest sys.dm_os_wait_stats, filtert irrelevante System-Waits heraus und berechnet den prozentualen Anteil je Wait-Typ.
# Alle Top-Waits einer Instanz
Get-sqmWaitStatistics -SqlInstance "SQL-PROD-01" -Top 10
# Nur kritische Wait-Typen (Threshold > 5 %)
Get-sqmWaitStatistics -SqlInstance "SQL-PROD-01" `
-MinPercent 5 -ExcludeKnownIdle
# Mehrere Instanzen parallel
$instances = "SQL-01", "SQL-02", "SQL-03"
$instances | ForEach-Object -Parallel {
Get-sqmWaitStatistics -SqlInstance $_
} | Sort-Object WaitPercent -Descending
Ausgabe-Mockup — Top Wait Types (SQL-PROD-01)
| WaitType | WaitMs | Pct | Kategorie |
|---|---|---|---|
| CXPACKET | 1.284.320 | 38.4 | Parallelism |
| PAGEIOLATCH_SH | 724.810 | 21.7 | I/O |
| LCK_M_X | 474.500 | 14.2 | Locking |
| SOS_SCHEDULER_YIELD | 297.140 | 8.9 | CPU |
| ASYNC_NETWORK_IO | 170.330 | 5.1 | Network |
| WRITELOG | 126.900 | 3.8 | I/O |
Query-Diagnose
Liest sys.dm_exec_requests kombiniert mit sys.dm_exec_sql_text und sys.dm_exec_query_plan — liefert eine sofortige Momentaufnahme aller aktiven Abfragen über dem Schwellwert.
sys.dm_exec_query_plan# Alle Abfragen laenger als 5 Sekunden
Get-sqmLongRunningQueries `
-SqlInstance "SQL-PROD-01" `
-ThresholdMs 5000
# Mit Blocking-Filter und Export
Get-sqmLongRunningQueries `
-SqlInstance "SQL-PROD-01" `
-ThresholdMs 1000 `
-IncludeBlocking |
Export-Csv "C:\Reports\LongQueries.csv" `
-NoTypeInformation
Index-Optimierung
Wertet sys.dm_db_missing_index_details + sys.dm_db_missing_index_group_stats aus. Gibt Impact-Score, Tabelle, Spalten und fertiges CREATE INDEX Statement zurück.
# Fehlende Indexes mit Impact > 60
Get-sqmMissingIndexes `
-SqlInstance "SQL-PROD-01" `
-Database "DWH_Produktion" `
-MinImpact 60 |
Format-Table Tabelle, ImpactScore, `
IndexStatement -AutoSize
Liest sys.dm_db_index_physical_stats und klassifiziert: REBUILD (Frag > 30 %), REORGANIZE (10–30 %), OK (unter 10 %).
# Fragmentierung aller Indexes
Get-sqmIndexFragmentation `
-SqlInstance "SQL-PROD-01" `
-Database "DWH_Produktion" `
-MinFragmentation 10 |
Where-Object { $_.Empfehlung -eq 'REBUILD' } |
Export-Csv "Rebuild_List.csv"
Query-Diagnose
Aktiviert den Query Store auf einer oder mehreren Datenbanken, konfiguriert Capture Mode und Retention, und liest Top-regressive Abfragen mit Plan-Vergleich aus.
# Query Store aktivieren mit Standardkonfiguration
Invoke-sqmQueryStore `
-SqlInstance "SQL-PROD-01" `
-Database "AppDB" `
-Action "Enable" `
-CaptureMode "Auto" `
-RetentionDays 30
# Top-5 plan-regressive Abfragen der letzten 7 Tage
Invoke-sqmQueryStore `
-SqlInstance "SQL-PROD-01" `
-Database "AppDB" `
-Action "GetTopRegressed" `
-Days 7 -Top 5
-Action ForcePlan -QueryID 142 wird ein stabiler Plan erzwungen — sofortige Rückkehr zur alten Performance ohne Code-Änderung.
Tracing & Diagnose
Erstellt, startet und stoppt Extended Events Sessions für Deadlock-Tracing und Long-Query-Monitoring — kein Profiler, kein Trace-Flag.
# Deadlock-XE-Session erstellen
Invoke-sqmExtendedEvents `
-SqlInstance "SQL-PROD-01" `
-Action "CreateDeadlockSession" `
-SessionName "sqm_deadlock_trace" `
-TargetPath "D:\XE\deadlocks"
# Long-Query-Session (ab 3 Sekunden)
Invoke-sqmExtendedEvents `
-SqlInstance "SQL-PROD-01" `
-Action "CreateLongQuerySession" `
-ThresholdMs 3000 `
-SessionName "sqm_longquery"
# Session stoppen und Events auslesen
Invoke-sqmExtendedEvents `
-SqlInstance "SQL-PROD-01" `
-Action "ReadAndStop" `
-SessionName "sqm_longquery"
XE-Session für xml_deadlock_report — schreibt XEL-Dateien auf Disk. Basis für Get-sqmDeadlockReport.
Trackt sql_statement_completed mit Filter auf duration > Threshold. Erfasst Query-Text, Plan-Handle, Wait-Info.
Lebenszyklus-Management der Session ohne manuelles T-SQL.
Liest Events aus dem Ring Buffer oder XEL-File, stoppt Session, gibt PSObject-Array zurück.
-TargetPath archiviert. Bei fehlendem Pfad fällt die Session auf Ring Buffer zurück.
Baseline & Monitoring
Nimmt vor einem Change einen Snapshot wichtiger Performance-Kennzahlen und vergleicht ihn nach dem Change — objektive Aussage über Verbesserung oder Verschlechterung.
# Snapshot VOR dem Change speichern
Invoke-sqmPerfBaseline `
-SqlInstance "SQL-PROD-01" `
-Action "Snapshot" `
-Label "vor_Index_Change" `
-OutputPath "D:\Baseline"
# ... Change durchfuehren ...
# Snapshot NACH dem Change
Invoke-sqmPerfBaseline `
-SqlInstance "SQL-PROD-01" `
-Action "Snapshot" `
-Label "nach_Index_Change" `
-OutputPath "D:\Baseline"
# Vergleich der beiden Snapshots
Invoke-sqmPerfBaseline `
-Action "Compare" `
-BaselinePath "D:\Baseline\vor_Index_Change.json" `
-ComparePath "D:\Baseline\nach_Index_Change.json"
Vergleichs-Report (Auszug)
| Kennzahl | Vorher | Nachher | Delta |
|---|---|---|---|
| Avg Query Duration (ms) | 1.243 | 312 | -74.9 % |
| Logical Reads / Batch | 4.821.332 | 287.440 | -94.0 % |
| PAGEIOLATCH_SH Wait (ms) | 724.810 | 48.220 | -93.3 % |
| CPU Zeit / Batch (ms) | 14.440 | 3.120 | -78.4 % |
| LCK_M_X Wait (ms) | 474.500 | 471.900 | -0.5 % |
Ressourcen-Monitoring
Liest sys.dm_exec_sessions und sys.dm_exec_connections — zeigt aktive Verbindungen gruppiert nach Login, Host und Status.
# Verbindungsstatistiken abrufen
Get-sqmConnectionStats `
-SqlInstance "SQL-PROD-01" `
-GroupBy "LoginName"
# Schlafende Sessions laenger als 10 Min
Get-sqmConnectionStats `
-SqlInstance "SQL-PROD-01" `
-Status "sleeping" `
-MinIdleMinutes 10
Liest Windows PerfMon-Zähler via sys.dm_os_performance_counters oder WMI — keine Remote-Verbindung zum OS benötigt.
# Wichtige SQL-PerfMon-Zaehler
Get-sqmPerfCounters `
-SqlInstance "SQL-PROD-01" `
-Category "SQLServer:Buffer Manager", `
"SQLServer:SQL Statistics", `
"SQLServer:Memory Manager"
# Als kontinuierliches Sampling (10s Intervall)
Get-sqmPerfCounters `
-SqlInstance "SQL-PROD-01" `
-SampleCount 6 -IntervalSec 10
Deadlock-Analyse
Parst Deadlock-XML aus dem System Health XE-Target oder aus eigenen XEL-Dateien und gibt eine lesbare, strukturierte Zusammenfassung je Deadlock-Ereignis aus.
# Deadlocks aus System Health (letzte 7 Tage)
Get-sqmDeadlockReport `
-SqlInstance "SQL-PROD-01" `
-Source "SystemHealth" `
-Days 7
# Aus eigener XEL-Datei lesen
Get-sqmDeadlockReport `
-SqlInstance "SQL-PROD-01" `
-Source "XelFile" `
-XelPath "D:\XE\deadlocks\sqm_deadlock*.xel"
# Als HTML-Report exportieren
Get-sqmDeadlockReport `
-SqlInstance "SQL-PROD-01" `
-Source "SystemHealth" `
-Days 30 |
ConvertTo-Html -Title "Deadlock Report" |
Out-File "DeadlockReport.html"
Schnellübersicht
| Funktion | Kategorie | Hauptparameter | Rückgabe | DMV / Quelle |
|---|---|---|---|---|
| Get-sqmWaitStatistics | Wait | -Top, -MinPercent, -ExcludeKnownIdle | PSObject[] | dm_os_wait_stats |
| Get-sqmLongRunningQueries | Query | -ThresholdMs, -IncludeBlocking | PSObject[] | dm_exec_requests |
| Get-sqmMissingIndexes | Index | -Database, -MinImpact | PSObject[] | dm_db_missing_index_* |
| Get-sqmIndexFragmentation | Index | -Database, -MinFragmentation | PSObject[] | dm_db_index_physical_stats |
| Invoke-sqmQueryStore | Query | -Action, -Days, -Top | PSObject[] / void | query_store_* |
| Invoke-sqmExtendedEvents | Tracing | -Action, -SessionName, -ThresholdMs | PSObject[] / void | XE Engine |
| Invoke-sqmPerfBaseline | Baseline | -Action, -Label, -OutputPath | PSObject[] / JSON | DMVs / JSON-File |
| Get-sqmConnectionStats | Ressource | -GroupBy, -Status, -MinIdleMinutes | PSObject[] | dm_exec_sessions |
| Get-sqmPerfCounters | Ressource | -Category, -SampleCount, -IntervalSec | PSObject[] | dm_os_performance_counters |
| Get-sqmDeadlockReport | Deadlock | -Source, -Days, -XelPath | PSObject[] | System Health / XEL |
Fazit
Skriptbasierte Diagnose ist wiederholbar, versionierbar und in CI/CD-Pipelines oder Monitoring-Jobs einbettbar. Kein "das hab ich mal schnell im SSMS gemacht".
Kein Schema-Änderung, keine zusätzliche Datenbank. Das Modul liest ausschließlich DMVs, System-Kataloge und optionale XEL-Dateien.
Uwe Janke · Senior SQL Server DBA · dtcSoftware · 2026
GitHub → sqmSQLTool