====== Identify long-running queries ====== Here's how to identify long-running queries using extended events. -- Create an extended events session: .. /* ALTER EVENT SESSION QueryMonitor ON SERVER STATE = STOP DROP EVENT SESSION QueryMonitor ON SERVER --*/ CREATE EVENT SESSION QueryMonitor ON SERVER ADD EVENT sqlserver.sql_statement_completed ( ACTION( sqlserver.session_server_principal_name ) WHERE duration > 5000000 -- microseconds ) ADD TARGET package0.ring_buffer WITH ( EVENT_RETENTION_MODE = NO_EVENT_LOSS , MAX_DISPATCH_LATENCY = 1 SECONDS ) ALTER EVENT SESSION QueryMonitor ON SERVER STATE = START * ''ADD EVENT sqlserver.sql_statement_completed'' causes an event to fire whenever a single SQL statement((For monitoring batch completion, the event ''sqlserver.sql_batch_completed'' was introduced in SQL Server 2012. Note that in this case you may want the full batch SQL text rather than the SQL //statement// included in the default output -- you can specify this in the ''ACTION'' clause as ''sqlserver.sql_text'')) completes. * The ''ACTION'' clause adds a user identifier to the output (not included by default). ** The ''WHERE'' clause restricts the recording of events to those where the SQL statement's execution duration exceeds five seconds (specified in **microseconds**). -- Run some queries -- Inspect the event data: .. ;WITH cte AS ( SELECT CAST(xet.target_data AS XML) AS TargetData FROM sys.dm_xe_session_targets AS xet INNER JOIN sys.dm_xe_sessions AS xe ON xe.[address] = xet.event_session_address WHERE xe.name = 'QueryMonitor' ), shred AS ( SELECT ev.value('(@timestamp)[1]', 'DATETIME') AS QueryEndTime , ev.query('(data[@name="statement"])').value('(//data/value)[1]', 'NVARCHAR(MAX)') AS SqlStatement , (ev.query('(data[@name="duration"])').value('(//data/value)[1]', 'BIGINT') + 500 )/ 1000 AS DurationMillis , ev.query('(action[@name="session_server_principal_name"])').value('(//action/value)[1]', 'NVARCHAR(MAX)') AS UserName FROM cte CROSS APPLY cte.TargetData.nodes('//RingBufferTarget/event') n(ev) ) SELECT DATEADD(MILLISECOND, -DurationMillis, QueryEndTime) AS QueryStartTime , QueryEndTime , (DurationMillis + 500 )/ 1000 AS DurationSecs , UserName , SqlStatement FROM shred ORDER BY QueryEndTime DESC Data for your event session is returned from ''sys.dm_xe_session_targets'' as a single XML field -- you can see this by executing the CTE definition alone -- which must then be shredded. Shredding can be slow, so an appropriately-restrictive ''WHERE'' clause in the event session definition is important to limit the amount of XML generated. ===== Further information ===== ** The ''sys.dm_xe_sessions'' DMV returns information about active extended events sessions. .. SELECT * FROM sys.dm_xe_sessions * [[admin:useful_extended_events_objects]] {{tag> extended_events statistics admin}}