Performance-Insights im SSMS: Flaschenhälse schneller erkennen ohne zusätzliche Tools

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

  1. Rechtsklick auf Datenbank → Intelligent Query Processing
  2. Tab „Plan Regression“
  3. 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.

Kategorien:

Keine Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert