|
| 1 | +/* ---------------------------------------------------------------------- |
| 2 | + Kontext-Check: Verbindung, DB, Login/Host/Client und Serverzeit |
| 3 | + Zweck: Verifiziert, gegen welchen Server/DB/Benutzer/Client du arbeitest. |
| 4 | +---------------------------------------------------------------------- */ |
| 5 | +SELECT |
| 6 | + @@SERVERNAME AS server_name, |
| 7 | + DB_NAME() AS current_database, |
| 8 | + SUSER_SNAME() AS login_name, |
| 9 | + HOST_NAME() AS host_name, |
| 10 | + PROGRAM_NAME() AS program_name, |
| 11 | + SYSDATETIMEOFFSET() AS server_time; |
| 12 | + |
| 13 | + |
| 14 | +/* ---------------------------------------------------------------------- |
| 15 | + (1) Parameter: Zielprozedur und Suchmuster |
| 16 | + - @ProcName: Name der gesuchten Stored Procedure. |
| 17 | + - @LikeText: Freitext-Suchmuster für SQL-Text (heuristisch). |
| 18 | + - @MyLogin/@MyHost/@MyProg: Umgebung des aktuellen Clients (optional nützlich). |
| 19 | + - @SSMSFilter: Filter auf SSMS-Clients (anpassbar für ADS o. ä.). |
| 20 | +---------------------------------------------------------------------- */ |
| 21 | +DECLARE @ProcName SYSNAME = N'dbo.usp_Lookup_LW_Order_LW'; |
| 22 | +DECLARE @LikeText NVARCHAR(200)= N'%usp_Lookup_LW_Order_LW%'; |
| 23 | + |
| 24 | +DECLARE @MyLogin SYSNAME = SUSER_SNAME(); |
| 25 | +DECLARE @MyHost NVARCHAR(128) = HOST_NAME(); |
| 26 | +DECLARE @MyProg NVARCHAR(128) = PROGRAM_NAME(); |
| 27 | + |
| 28 | +DECLARE @SSMSFilter NVARCHAR(200) = N'%Microsoft SQL Server Management Studio%'; |
| 29 | + |
| 30 | + |
| 31 | +/* ---------------------------------------------------------------------- |
| 32 | + (2) Ziel-Session (SPID) ermitteln: |
| 33 | + - Sammelt passende aktive Requests in @m (ohne die eigene Session). |
| 34 | + - Filter über SQL-Text (@LikeText) oder EXEC-Aufruf der Prozedur. |
| 35 | + - Stellt sicher, dass genau 1 Treffer existiert -> sonst THROW. |
| 36 | + Ergebnis: @target_spid enthält die eindeutige Ziel-Session. |
| 37 | +---------------------------------------------------------------------- */ |
| 38 | +DECLARE @target_spid INT; |
| 39 | + |
| 40 | +DECLARE @m TABLE |
| 41 | +( |
| 42 | + session_id INT PRIMARY KEY, |
| 43 | + start_time DATETIME2, |
| 44 | + login_name SYSNAME, |
| 45 | + host_name NVARCHAR(128), |
| 46 | + program_name NVARCHAR(128) |
| 47 | +); |
| 48 | + |
| 49 | +INSERT INTO @m (session_id, start_time, login_name, host_name, program_name) |
| 50 | +SELECT |
| 51 | + r.session_id, |
| 52 | + r.start_time, |
| 53 | + s.login_name, |
| 54 | + s.host_name, |
| 55 | + s.program_name |
| 56 | +FROM sys.dm_exec_requests AS r |
| 57 | +JOIN sys.dm_exec_sessions AS s ON s.session_id = r.session_id |
| 58 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t |
| 59 | +WHERE s.is_user_process = 1 |
| 60 | + AND r.session_id <> @@SPID |
| 61 | + AND (t.text LIKE @LikeText OR t.text LIKE N'%EXEC%'+@ProcName+'%'); |
| 62 | + |
| 63 | +-- 0 Treffer -> eindeutige Fehlermeldung |
| 64 | +IF NOT EXISTS (SELECT 1 FROM @m) |
| 65 | + THROW 51000, 'No matching session found. Refine your filter (LIKE/@ProcName).', 1; |
| 66 | + |
| 67 | +-- >1 Treffer -> eindeutige Fehlermeldung (oder hier Policy für TOP(1) wählen) |
| 68 | +IF (SELECT COUNT(*) FROM @m) > 1 |
| 69 | + THROW 51001, 'Multiple matching sessions found. Narrow your filter (login/host/program/proc).', 1; |
| 70 | + |
| 71 | +-- genau 1 Treffer -> SPID übernehmen |
| 72 | +SELECT @target_spid = session_id FROM @m; |
| 73 | + |
| 74 | +-- Optional: Sichtprüfung der gefundenen Session-Metadaten |
| 75 | +SELECT * FROM @m; |
| 76 | + |
| 77 | +PRINT(@target_spid); |
| 78 | + |
| 79 | + |
| 80 | +/* ---------------------------------------------------------------------- |
| 81 | + Detailblick auf die Ziel-Session (Request-Ebene): |
| 82 | + - Status/Command/Startzeit |
| 83 | + - Wartegründe (wait_type/last_wait_type/wait_time) |
| 84 | + - Blocker (blocking_session_id) |
| 85 | + - DB-Name und aktueller SQL-Text |
| 86 | + Zweck: Erste, schnelle Ursachenanalyse (Locks, Memory-Grant, I/O, etc.). |
| 87 | +---------------------------------------------------------------------- */ |
| 88 | +SELECT |
| 89 | + r.session_id, r.status, r.command, r.start_time, |
| 90 | + r.wait_type, r.last_wait_type, r.wait_time, r.blocking_session_id, |
| 91 | + DB_NAME(r.database_id) AS database_name, |
| 92 | + t.text AS sql_text |
| 93 | +FROM sys.dm_exec_requests r |
| 94 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t |
| 95 | +WHERE r.session_id = @target_spid; |
| 96 | + |
| 97 | + |
| 98 | +/* ---------------------------------------------------------------------- |
| 99 | + (2a) "Meine Requests" (hier: auf die Ziel-Session eingeschränkt): |
| 100 | + - Zeigt Laufzeit, Fortschritt (percent_complete, falls vorhanden), |
| 101 | + Blocker, DB und SQL-Text. |
| 102 | + Hinweis: percent_complete ist nur bei bestimmten Operationen > 0. |
| 103 | +---------------------------------------------------------------------- */ |
| 104 | +SELECT |
| 105 | + r.session_id, |
| 106 | + s.login_name, s.host_name, s.program_name, |
| 107 | + r.status, r.command, r.start_time, |
| 108 | + r.percent_complete, r.total_elapsed_time/1000.0 AS elapsed_s, |
| 109 | + r.blocking_session_id, |
| 110 | + DB_NAME(r.database_id) AS database_name, |
| 111 | + t.text AS sql_text |
| 112 | +FROM sys.dm_exec_requests AS r |
| 113 | +JOIN sys.dm_exec_sessions AS s |
| 114 | + ON s.session_id = r.session_id |
| 115 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t |
| 116 | +WHERE r.session_id = @target_spid |
| 117 | +ORDER BY r.start_time ASC; |
| 118 | + |
| 119 | + |
| 120 | +/* ---------------------------------------------------------------------- |
| 121 | + (3) Läuft noch meine Stored Procedure? |
| 122 | + - Hier kein heuristisches Muster mehr, sondern direkter Filter auf @target_spid. |
| 123 | + - Liefert Status, Command, Startzeit, Umgebung und SQL-Text. |
| 124 | + Zweck: Bestätigung, dass die ermittelte SPID wirklich "deine" Ausführung ist. |
| 125 | +---------------------------------------------------------------------- */ |
| 126 | +SELECT |
| 127 | + r.session_id, r.status, r.command, r.start_time, |
| 128 | + s.login_name, s.host_name, s.program_name, |
| 129 | + DB_NAME(r.database_id) AS database_name, |
| 130 | + t.text AS sql_text |
| 131 | +FROM sys.dm_exec_requests AS r |
| 132 | +JOIN sys.dm_exec_sessions AS s ON s.session_id = r.session_id |
| 133 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t |
| 134 | +WHERE s.is_user_process = 1 |
| 135 | + AND r.session_id = @target_spid |
| 136 | +ORDER BY r.start_time ASC; |
| 137 | + |
| 138 | + |
| 139 | +/* ---------------------------------------------------------------------- |
| 140 | + Status/Waits/Blocker & SQL-Text der Ziel-SPID: |
| 141 | + - Kompakte Ansicht für Troubleshooting (Warten, Blocker, DB, SQL). |
| 142 | +---------------------------------------------------------------------- */ |
| 143 | +SELECT r.session_id, r.status, r.command, r.start_time, |
| 144 | + r.wait_type, r.last_wait_type, r.wait_time, r.blocking_session_id, |
| 145 | + DB_NAME(r.database_id) AS db_name, |
| 146 | + t.text |
| 147 | +FROM sys.dm_exec_requests r |
| 148 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t |
| 149 | +WHERE r.session_id = @target_spid; |
| 150 | + |
| 151 | + |
| 152 | +/* ---------------------------------------------------------------------- |
| 153 | + Blocker-Hierarchie: |
| 154 | + - Zeigt an, welche Sessions andere blockieren (Kette). |
| 155 | + - Hier als Gesamtüberblick für alle mit Blocking; Fokus auf @target_spid |
| 156 | + folgt in der nächsten Abfrage "wer blockiert wen?". |
| 157 | +---------------------------------------------------------------------- */ |
| 158 | +;WITH c AS ( |
| 159 | + SELECT session_id, blocking_session_id |
| 160 | + FROM sys.dm_exec_requests WHERE blocking_session_id <> 0 |
| 161 | +) |
| 162 | +SELECT DISTINCT r.session_id AS victim, r.blocking_session_id AS blocker, |
| 163 | + vt.text AS victim_sql, bt.text AS blocker_sql |
| 164 | +FROM sys.dm_exec_requests r |
| 165 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) vt |
| 166 | +OUTER APPLY sys.dm_exec_sql_text((SELECT r2.sql_handle FROM sys.dm_exec_requests r2 WHERE r2.session_id=r.blocking_session_id)) bt |
| 167 | +WHERE r.blocking_session_id <> 0; |
| 168 | + |
| 169 | + |
| 170 | +/* ---------------------------------------------------------------------- |
| 171 | + Memory-Grant-Warteschlange (global): |
| 172 | + - Zeigt Sessions mit angeforderten/gewährten Speichermengen für Abfragen. |
| 173 | + - Hohe wait_time_ms + granted_memory_kb = 0 deuten auf Engpässe hin. |
| 174 | +---------------------------------------------------------------------- */ |
| 175 | +SELECT session_id, requested_memory_kb, granted_memory_kb, |
| 176 | + required_memory_kb, max_used_memory_kb, wait_time_ms |
| 177 | +FROM sys.dm_exec_query_memory_grants |
| 178 | +WHERE session_id = @target_spid |
| 179 | +ORDER BY wait_time_ms DESC; |
| 180 | + |
| 181 | + |
| 182 | +/* ---------------------------------------------------------------------- |
| 183 | + Wer blockiert wen? (inkl. Kette) – auf die Ziel-Session fokussiert: |
| 184 | + - Baut eine Kette von Blockings auf und filtert dann @target_spid. |
| 185 | + - Erkennt schnell, ob die Ziel-Session Opfer in einer Blocker-Kette ist. |
| 186 | +---------------------------------------------------------------------- */ |
| 187 | +;WITH blockers AS ( |
| 188 | + SELECT |
| 189 | + r.session_id, |
| 190 | + r.blocking_session_id, |
| 191 | + CAST(CONCAT(r.session_id, N'') AS NVARCHAR(4000)) AS chain |
| 192 | + FROM sys.dm_exec_requests AS r |
| 193 | + WHERE r.blocking_session_id <> 0 |
| 194 | + UNION ALL |
| 195 | + SELECT |
| 196 | + r.session_id, |
| 197 | + r.blocking_session_id, |
| 198 | + CAST(b.chain + N' -> ' + CAST(r.session_id AS NVARCHAR(10)) AS NVARCHAR(4000)) AS chain |
| 199 | + FROM sys.dm_exec_requests AS r |
| 200 | + JOIN blockers b ON r.blocking_session_id = b.session_id |
| 201 | + WHERE r.blocking_session_id <> 0 |
| 202 | +) |
| 203 | +SELECT DISTINCT |
| 204 | + s.session_id, |
| 205 | + s.login_name, s.host_name, s.program_name, |
| 206 | + r.status, r.command, r.start_time, |
| 207 | + r.blocking_session_id, |
| 208 | + b.chain |
| 209 | +FROM sys.dm_exec_sessions s |
| 210 | +LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id |
| 211 | +LEFT JOIN blockers b ON s.session_id = b.session_id |
| 212 | +WHERE s.is_user_process = 1 |
| 213 | + AND s.session_id = @target_spid |
| 214 | +ORDER BY s.session_id; |
| 215 | + |
| 216 | + |
| 217 | +/* ---------------------------------------------------------------------- |
| 218 | + Ausführungsplan (aktuell) der Ziel-Session: |
| 219 | + - Liefert Plan XML (query_plan) + SQL-Text; hilfreich zur Plananalyse. |
| 220 | + - Hinweis: Nicht jeder Request liefert einen Plan (z. B. kurze/laufende). |
| 221 | +---------------------------------------------------------------------- */ |
| 222 | +SELECT TOP (20) |
| 223 | + r.session_id, r.status, r.command, r.start_time, |
| 224 | + DB_NAME(r.database_id) AS database_name, |
| 225 | + t.text AS sql_text, |
| 226 | + qp.query_plan |
| 227 | +FROM sys.dm_exec_requests AS r |
| 228 | +OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t |
| 229 | +OUTER APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp |
| 230 | +WHERE r.session_id = @target_spid |
| 231 | +ORDER BY r.start_time ASC; |
| 232 | + |
| 233 | + |
| 234 | +/* ---------------------------------------------------------------------- |
| 235 | + Aktive Transaktionen der Ziel-Session: |
| 236 | + - Verknüpft Session -> SessionTransactions -> ActiveTransactions -> DB/Log. |
| 237 | + - Zeigt Typ/Status/Begin-Zeitpunkt und Log-Verbrauch pro DB. |
| 238 | + Zweck: Prüfen, ob lange/umfangreiche Transaktionen die Ursache sind. |
| 239 | +---------------------------------------------------------------------- */ |
| 240 | +SELECT |
| 241 | + s.session_id, |
| 242 | + at.transaction_id, |
| 243 | + at.name, |
| 244 | + at.transaction_begin_time, |
| 245 | + at.transaction_type, -- 1=Read/Write, 2=Read-only, 3=System, 4=Distributed |
| 246 | + at.transaction_state, -- 0..8 (2=Active, 6=Committed, 7=Rolled back, ...) |
| 247 | + dt.database_id, |
| 248 | + DB_NAME(dt.database_id) AS database_name, |
| 249 | + dt.database_transaction_log_bytes_used/1024.0/1024.0 AS log_used_MB |
| 250 | +FROM sys.dm_exec_sessions AS s |
| 251 | +JOIN sys.dm_tran_session_transactions AS st ON st.session_id = s.session_id |
| 252 | +JOIN sys.dm_tran_active_transactions AS at ON at.transaction_id = st.transaction_id |
| 253 | +LEFT JOIN sys.dm_tran_database_transactions AS dt ON dt.transaction_id = at.transaction_id |
| 254 | +WHERE s.is_user_process = 1 |
| 255 | + AND s.session_id = @target_spid |
| 256 | +ORDER BY at.transaction_begin_time; |
0 commit comments