sqmSQLTool  ·  Performance & Diagnose  ·  2026

Performance &
Diagnose

Engpässe in Minuten statt Stunden finden — direkt aus PowerShell, ohne externe Tools.

Wait-Analyse DMV-Reports Query Store Extended Events Baseline Index-Diagnose

Uwe Janke  ·  Senior SQL Server DBA  ·  dtcSoftware

sqmSQLTool — Wait Statistics Report
Server: SQL-PROD-01  |  28.05.2026 09:14
CXPACKET38.4 %
PAGEIOLATCH_SH21.7 %
LCK_M_X14.2 %
SOS_SCHEDULER_YIELD8.9 %
ASYNC_NETWORK_IO5.1 %
WRITELOG3.8 %
Dauer > 500 ms
Queries > 500 ms47
Avg. Dauer (ms)1.243
Max. Dauer (ms)18.720
Missing Indexes
Impact > 803
Impact 50-808
Fragmentation > 30%12

Warum sqmSQLTool Performance & Diagnose?

Typische Herausforderungen im Alltag

Ohne strukturierte Diagnose-Werkzeuge bleibt die Ursachenforschung mühsam und zeitraubend.

🚫

Kein Baseline-Vergleich

Langsame Abfragen existieren — aber niemand weiss, ob sie schon immer so waren oder sich nach einem Change verschlechtert haben.

🔍

Wait Stats unbekannt

sys.dm_os_wait_stats liefert Rohdaten. Ohne Normalisierung und Filterung erkennt man Engpässe nicht auf einen Blick.

⚠️

Query Store nicht aktiviert

In vielen Umgebungen ist der Query Store deaktiviert oder nicht konfiguriert — dabei ist er das wirksamste Werkzeug gegen Plan-Regressionen.

📊

Index-Empfehlungen verpuffen

DMVs wie sys.dm_db_missing_index_details liefern wertvolle Hinweise, werden aber selten systematisch ausgewertet.

sqmSQLTool fasst alle Diagnose-Schritte in PowerShell-Cmdlets zusammen — reproduzierbar, skriptbar und für mehrere Instanzen parallel ausführbar.

Funktionsüberblick

Vier Diagnose-Kategorien

Alle Funktionen sind in sich geschlossen und können einzeln oder kombiniert in Monitoring-Skripten eingesetzt werden.

Wait-Analyse

  • Get-sqmWaitStatistics
  • Get-sqmConnectionStats
  • Get-sqmPerfCounters
🔎

Query-Diagnose

  • Get-sqmLongRunningQueries
  • Invoke-sqmQueryStore
  • Get-sqmDeadlockReport
🔧

Index-Optimierung

  • Get-sqmMissingIndexes
  • Get-sqmIndexFragmentation
📈

Baseline & Tracing

  • Invoke-sqmPerfBaseline
  • Invoke-sqmExtendedEvents
PowerShell Session
sqmSQLTool Module
SQL Server DMVs / XE / Query Store
Strukturierter Report / PSObject
Rückgabewerte sind immer PSCustomObject-Arrays — direkt an Export-Csv, ConvertTo-Html oder Send-MailMessage weiterleitbar.

Wait-Analyse

Get-sqmWaitStatistics

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
ExcludeKnownIdle filtert Sleep, WAITFOR, BROKER_TO_FLUSH und ähnliche Idle-Waits automatisch heraus — der Report zeigt nur aktive Engpässe.

Ausgabe-Mockup — Top Wait Types (SQL-PROD-01)

Get-sqmWaitStatistics — SQL-PROD-01
WaitType WaitMs Pct Kategorie
CXPACKET1.284.32038.4Parallelism
PAGEIOLATCH_SH724.81021.7I/O
LCK_M_X474.50014.2Locking
SOS_SCHEDULER_YIELD297.1408.9CPU
ASYNC_NETWORK_IO170.3305.1Network
WRITELOG126.9003.8I/O
Gesamt Wait Time: 3.343.900 ms  |  Messzeitraum: seit letztem Restart
sys.dm_os_wait_stats-ExcludeKnownIdle-Top N-MinPercent

Query-Diagnose

Get-sqmLongRunningQueries

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.

Was wird erfasst?

  • Abfrage-Text (gekürzt auf 500 Zeichen)
  • Plan-Handle für direkten Aufruf von sys.dm_exec_query_plan
  • Aktuelle Wait-Type und Wait-Dauer
  • Login-Name, Host-Name, Datenbank
  • CPU-Zeit, Lese-/Schreibzähler, Dauer in ms
  • Blocking-Session-ID (falls vorhanden)
# 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
LongRunningQueries — Threshold: 5.000 ms
SQL-PROD-01  |  28.05.2026 09:22:14
SPID72
Loginsvc_etl@domain.local
DatenbankDWH_Produktion
Dauer (ms)18.720
CPU (ms)14.440
Wait TypePAGEIOLATCH_SH
Blocking SPID0
Logical Reads4.821.332
Query (gekürzt)
SELECT f.*, d.Region FROM Fact_Sales f JOIN Dim_Region d ON f.RegionID = d.ID WHERE f.Datum >= '2026-01-01' ...
Hinweis: Bei Blocking-Chains den Parameter -IncludeBlocking setzen — dann wird der Head-Blocker zusätzlich mit ausgegeben.

Index-Optimierung

Get-sqmMissingIndexes & Get-sqmIndexFragmentation

Get-sqmMissingIndexes

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
Missing Indexes — DWH_Produktion
Fact_Sales (Impact 94)INCLUDE RegionID
Dim_Customer (Impact 81)ON CustomerKey
Fact_Orders (Impact 67)ON OrderDate, Status

Get-sqmIndexFragmentation

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"
Index Fragmentation — Auswahl
Fact_Sales.IX_Date67 % → REBUILD
Fact_Orders.PK41 % → REBUILD
Dim_Product.IX_Cat18 % → REORG
Dim_Customer.PK4 % → OK

Query-Diagnose

Invoke-sqmQueryStore

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 & konfigurieren

# 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
Force Plan: Mit -Action ForcePlan -QueryID 142 wird ein stabiler Plan erzwungen — sofortige Rückkehr zur alten Performance ohne Code-Änderung.
Query Store — Top Regressed Queries (AppDB, letzte 7 Tage)
QueryID 142 — usp_GetOrderSummary
Avg. Dauer vorher (ms)87
Avg. Dauer jetzt (ms)3.240
Plan-Wechsel am25.05.2026
Alter Plan IDPlanID 88
Neuer Plan IDPlanID 201 (Scan!)
QueryID 87 — fn_CalcDiscount
Avg. Dauer vorher (ms)12
Avg. Dauer jetzt (ms)890
EmpfehlungStatistik aktualisieren
sys.query_store_querysys.query_store_planForce PlanCaptureMode

Tracing & Diagnose

Invoke-sqmExtendedEvents

Erstellt, startet und stoppt Extended Events Sessions für Deadlock-Tracing und Long-Query-Monitoring — kein Profiler, kein Trace-Flag.

Deadlock-Session anlegen & starten

# 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"

Unterstützte Actions

1
CreateDeadlockSession

XE-Session für xml_deadlock_report — schreibt XEL-Dateien auf Disk. Basis für Get-sqmDeadlockReport.

2
CreateLongQuerySession

Trackt sql_statement_completed mit Filter auf duration > Threshold. Erfasst Query-Text, Plan-Handle, Wait-Info.

3
Start / Stop / Drop

Lebenszyklus-Management der Session ohne manuelles T-SQL.

4
ReadAndStop

Liest Events aus dem Ring Buffer oder XEL-File, stoppt Session, gibt PSObject-Array zurück.

XEL-Dateien werden automatisch auf -TargetPath archiviert. Bei fehlendem Pfad fällt die Session auf Ring Buffer zurück.

Baseline & Monitoring

Invoke-sqmPerfBaseline

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)

Baseline Compare — SQL-PROD-01
Vorher: vor_Index_Change  |  Nachher: nach_Index_Change
KennzahlVorherNachherDelta
Avg Query Duration (ms)1.243312-74.9 %
Logical Reads / Batch4.821.332287.440-94.0 %
PAGEIOLATCH_SH Wait (ms)724.81048.220-93.3 %
CPU Zeit / Batch (ms)14.4403.120-78.4 %
LCK_M_X Wait (ms)474.500471.900-0.5 %
Snapshots werden als JSON gespeichert und sind revisionssicher. Ideal für Change-Dokumentation in einem CR-Prozess.

Ressourcen-Monitoring

Get-sqmConnectionStats & Get-sqmPerfCounters

Get-sqmConnectionStats

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
Connection Stats — by Login
svc_app@domain84 aktiv
svc_etl@domain23 (davon 14 sleeping)
SSRS_Service12 aktiv
sa2 (Prüfen!)

Get-sqmPerfCounters

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
PerfCounters — SQL-PROD-01
Buffer Cache Hit Ratio98.7 %
Page Life Expectancy284 s
Batch Requests/sec1.420
SQL Compilations/sec88 (hoch!)
Memory Grants Pending4

Deadlock-Analyse

Get-sqmDeadlockReport

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"
Das SQL-Deadlock-XML kann über 100 kB groß sein. sqmSQLTool extrahiert nur die relevanten Knoten: beteiligte Prozesse, Ressourcen, Opfer-SPID und SQL-Text.
Deadlock Report — SQL-PROD-01 (letzte 7 Tage)
Deadlock #1  |  26.05.2026 22:14:08
Opfer-SPIDSPID 114
Opfer-Loginsvc_etl@domain.local
Opfer-QueryUPDATE Fact_Sales SET ...
Gewinner-SPIDSPID 87
Gewinner-Loginsvc_app@domain.local
RessourceFact_Sales.IX_Date (RID Lock)
Deadlock #2  |  27.05.2026 03:42:51
Opfer-SPIDSPID 203
RessourceDim_Customer.PK (Key Lock)
EmpfehlungREAD_COMMITTED_SNAPSHOT aktivieren
xml_deadlock_reportSystem HealthXEL-FileRCSI

Schnellübersicht

Alle 10 Diagnose-Funktionen auf einen Blick

Funktion Kategorie Hauptparameter Rückgabe DMV / Quelle
Get-sqmWaitStatisticsWait-Top, -MinPercent, -ExcludeKnownIdlePSObject[]dm_os_wait_stats
Get-sqmLongRunningQueriesQuery-ThresholdMs, -IncludeBlockingPSObject[]dm_exec_requests
Get-sqmMissingIndexesIndex-Database, -MinImpactPSObject[]dm_db_missing_index_*
Get-sqmIndexFragmentationIndex-Database, -MinFragmentationPSObject[]dm_db_index_physical_stats
Invoke-sqmQueryStoreQuery-Action, -Days, -TopPSObject[] / voidquery_store_*
Invoke-sqmExtendedEventsTracing-Action, -SessionName, -ThresholdMsPSObject[] / voidXE Engine
Invoke-sqmPerfBaselineBaseline-Action, -Label, -OutputPathPSObject[] / JSONDMVs / JSON-File
Get-sqmConnectionStatsRessource-GroupBy, -Status, -MinIdleMinutesPSObject[]dm_exec_sessions
Get-sqmPerfCountersRessource-Category, -SampleCount, -IntervalSecPSObject[]dm_os_performance_counters
Get-sqmDeadlockReportDeadlock-Source, -Days, -XelPathPSObject[]System Health / XEL
Alle Funktionen unterstützen -SqlInstance als ersten Parameter und akzeptieren Credential-Objekte über -Credential. Pipeline-Input ist möglich.

Fazit

Was das Team mit sqmSQLTool Performance & Diagnose gewinnt

10
Diagnose-Funktionen
Von Wait-Analyse bis Deadlock-Report — alles in einem Modul, kein Toolwechsel.
0
Extra-Tools
Kein Profiler, kein SSMS-Wizard, kein separates Monitoring-Agent — nur PowerShell.
n
Instanzen parallel
ForEach-Object -Parallel ermöglicht gleichzeitige Diagnose über die gesamte Instanz-Landschaft.

Reproduzierbarkeit

Skriptbasierte Diagnose ist wiederholbar, versionierbar und in CI/CD-Pipelines oder Monitoring-Jobs einbettbar. Kein "das hab ich mal schnell im SSMS gemacht".

Sofort einsatzbereit

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