Warum ich keine externen Tools brauche
SSMS 20xx bringt inzwischen alles mit, was ich für erste Analysen brauche.
Keine Drittanbieter, kein Profiler, kein PowerShell-Massaker.
Ich zeige Dir, wie ich Performance-Probleme direkt im SQL Server Management Studio erkenne und einordne – mit Tuning Bordmitteln.
1. Abfragen mit hoher CPU-Zeit identifizieren
SELECT TOP 10
qs.total_worker_time / qs.execution_count AS avg_cpu_time,
qs.execution_count,
qs.total_worker_time,
SUBSTRING(st.text, qs.statement_start_offset / 2 + 1,
(CASE
WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), st.text)) * 2
ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2) AS query_text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY avg_cpu_time DESC;
Hilft sofort bei: „Der Server ist lahm, aber ich weiß nicht, was läuft.“
2. Abfragen mit vielen logischen Lesezugriffen
SELECT TOP 10
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
qs.execution_count,
st.text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY avg_logical_reads DESC;
Wenn hier simple SELECT *
-Abfragen auftauchen, weißt Du, was los ist.
3. Letzte teure Abfragen anzeigen
SELECT TOP 20
creation_time,
last_execution_time,
execution_count,
total_elapsed_time / 1000 AS total_ms,
SUBSTRING(st.text, qs.statement_start_offset / 2 + 1,
(CASE
WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), st.text)) * 2
ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY total_elapsed_time DESC;
Praktisch nach einer Lastspitze.
Zeigt, was zuletzt aus dem Ruder lief.
4. Aktive Wartezeiten (Waits) analysieren
SELECT TOP 10
wait_type,
wait_time_ms,
wait_time_ms * 100.0 / SUM(wait_time_ms) OVER() AS pct,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN (
'CLR_SEMAPHORE','LAZYWRITER_SLEEP','RESOURCE_QUEUE','SLEEP_TASK',
'SLEEP_SYSTEMTASK','SQLTRACE_BUFFER_FLUSH','WAITFOR','LOGMGR_QUEUE',
'CHECKPOINT_QUEUE','REQUEST_FOR_DEADLOCK_SEARCH','XE_TIMER_EVENT','BROKER_TO_FLUSH','BROKER_TASK_STOP','CLR_MANUAL_EVENT','CLR_AUTO_EVENT','DISPATCHER_QUEUE_SEMAPHORE','FT_IFTS_SCHEDULER_IDLE_WAIT','XE_DISPATCHER_WAIT','XE_DISPATCHER_JOIN','SQLTRACE_INCREMENTAL_FLUSH_SLEEP')
ORDER BY wait_time_ms DESC;
Hilft bei: „Es klemmt, aber ich sehe keinen Deadlock.“
5. Indizes ohne Wirkung
SELECT
OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
i.index_id,
user_seeks + user_scans + user_lookups + user_updates AS total_usage
FROM sys.dm_db_index_usage_stats us
INNER JOIN sys.indexes i ON us.object_id = i.object_id AND us.index_id = i.index_id
WHERE OBJECTPROPERTY(i.object_id,'IsUserTable') = 1
AND us.database_id = DB_ID()
AND user_seeks + user_scans + user_lookups = 0
ORDER BY total_usage ASC;
Wenn hier 20 Indizes mit total_usage = 0
stehen – weg damit.
6. Abfragen mit schlechtem Plan
SQL Server 2025: Last Known Good Plan direkt im SSMS
- Rechtsklick auf Datenbank → Intelligent Query Processing
- Tab „Plan Regression“
- Vergleich zwischen aktuellem und altem Plan
Oder per T-SQL:
SELECT
q.query_id,
p.plan_id,
p.is_forced_plan,
p.execution_type_desc,
p.last_execution_time,
q.query_sql_text
FROM sys.query_store_plan p
JOIN sys.query_store_query q ON p.query_id = q.query_id
WHERE p.execution_type_desc = 'Regular'
AND p.is_forced_plan = 0
ORDER BY p.last_execution_time DESC;
Wenn Du merkst, dass eine Abfrage früher lief und jetzt nicht mehr: alten Plan vergleichen oder „forcen“.
7. IO-Stress auf bestimmte Datenbank oder Datei
SELECT DB_NAME(database_id) AS database_name,
file_id,
io_stall_read_ms,
num_of_reads,
io_stall_write_ms,
num_of_writes
FROM sys.dm_io_virtual_file_stats(NULL, NULL);
Hilft bei „TempDB überlastet“ oder „Backup-Laufwerk langsam“.
8. TempDB: Wer ballert rein?
SELECT
s.session_id,
r.status,
r.command,
t.text,
tsu.user_objects_alloc_page_count AS user_pages,
tsu.internal_objects_alloc_page_count AS internal_pages
FROM sys.dm_db_task_space_usage tsu
JOIN sys.dm_exec_requests r ON tsu.session_id = r.session_id
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
ORDER BY user_pages DESC;
Nützlich bei Access-Nutzern, die versehentlich 100k Datensätze in ein Formular laden.
9. Empfehlung: Regelmäßige Snapshot-Skripte
Ich speichere mir morgens 7:30 und abends 17:00 alle Performance-Statistiken in Tabellen.
Dann sehe ich Trends.
Oder kann dem Chef zeigen, „ja, das war’s – jeden Tag dieselbe Abfrage“.
Mein Fazit aus 2025
SSMS bringt genug mit, um 90 % aller Performanceprobleme zu erkennen.
Was Du brauchst: gute Queries, eine Portion Neugier, ein Gefühl für Normalzustände.
Keine Antworten