The following code creates an extended event session that correlates wait_info and stored procedure (RPC calls) and allows you to analyze the data using Power BI.
Make sure to configure your right logfile path (where the Extended Event file is written and your Database ID)
Also enable xp_cmdshell to allow the script to cleanup the logfiles after the trace is dones.
USE [master]
GO
Alter Database PowerBITrace set single_user
Drop Database [PowerBITrace]
/****** Object: Database [PowerBITrace] Script Date: 12/1/2015 4:02:15 PM ******/
CREATE DATABASE [PowerBITrace]
GO
USE [PowerBITrace]
GO
/****** Object: StoredProcedure [dbo].[StpandWaitTrace] Script Date: 12/1/2015 4:02:16 PM ******/
CREATE Procedure [dbo].[StpandWaitTrace] (@duration varchar(10), @szenario varchar(50))
as
begin
--Author Lukas Steindl
--Script um Waitinfo Trace zu machen
--Schritt 1) TRACE ANLEGEN:
IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name = 'StoredProcedureAndWaitstats')
DROP EVENT SESSION [StoredProcedureAndWaitstats] ON SERVER
waitfor delay '00:00:02'
--CLEANUP FIRST:
--Truncate Table [dbo].[ProcedureExecutionTime]
--Truncate Table [dbo].[WaitInfo]
--Anpassen:
--sp_configure 'show advanced options',1
--reconfigure
--sp_configure 'xp_cmdshell',1
--reconfigure
--DB ID und Log pfad (wichtig SQL Server zugang zum Log drive! )
exec xp_cmdshell 'DEL /F "C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\Log\StoredProcedureAndWaitstats*"'
CREATE EVENT SESSION [StoredProcedureAndWaitstats] ON SERVER
ADD EVENT sqlos.wait_info(
WHERE ([package0].[equal_uint64]([sqlserver].[database_id],(5)) AND [duration]>(0) AND [package0].[not_equal_uint64]([wait_type],(109)) AND [package0].[not_equal_uint64]([wait_type],(96)) AND [package0].[not_equal_uint64]([wait_type],(798)))),
ADD EVENT sqlserver.rpc_completed(SET collect_statement=(1)
WHERE ([package0].[equal_uint64]([sqlserver].[database_id],(5)) AND [package0].[not_equal_unicode_string]([statement],N'exec sp_reset_connection')))
ADD TARGET package0.event_file(SET filename=N'C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\Log\StoredProcedureAndWaitstats.xel')
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)
--Schritt 2) TRACE STARTEN:
ALTER EVENT SESSION StoredProcedureAndWaitstats
ON SERVER
STATE = start;
waitfor delay @duration --'00:00:02'
--Schritt 3)
ALTER EVENT SESSION StoredProcedureAndWaitstats
ON SERVER
STATE = stop;
waitfor delay '00:00:10' --flushen!
--in temptable kopieren:
if OBJECT_ID('tempdb..#capture_stpandwaits_data') IS NOT NULL Drop Table #capture_stpandwaits_data
Select CAST(event_data as xml) AS event_data
into #capture_stpandwaits_data
from sys.fn_xe_file_target_read_file('C:\Program Files\Microsoft SQL Server\MSSQL12.SQL2014\MSSQL\Log\StoredProcedureAndWaitstats*.xel',null,null,null)
--Schritt 5) AUSWERTEN
Insert into ProcedureExecutionTime
Select [timestamp], cpu_time, duration_in_microseconds, physical_reads, logical_reads, writes, row_count, SqlText,
LEFT(Correlation,36) as 'Correlation',
REPLACE(RIGHT(Correlation,2),'-','') as 'Sequence'
,datepart(Minute,timestamp) as [Minute],datepart(second,timestamp) as [Second],datepart(MILLISECOND,timestamp) as [Millisecond],@szenario
from (
SELECT
n.value('(@timestamp)[1]', 'datetime2') AS [timestamp],
n.value('(data[@name="cpu_time"]/value)[1]', 'int') AS cpu_time,
n.value('(data[@name="duration"]/value)[1]', 'int') AS duration_in_microseconds,
n.value('(data[@name="physical_reads"]/value)[1]', 'int') AS physical_reads,
n.value('(data[@name="logical_reads"]/value)[1]', 'int') AS logical_reads,
n.value('(data[@name="writes"]/value)[1]', 'int') AS writes,
n.value('(data[@name="row_count"]/value)[1]', 'int') AS row_count,
n.value('(data[@name="statement"]/value)[1]', 'nvarchar(512)') AS SqlText,
n.value('(action[@name="attach_activity_id"]/value)[1]', 'varchar(512)') AS Correlation
FROM
#capture_stpandwaits_data
CROSS APPLY event_data.nodes('event')as q(n)
where n.value('(@name)[1]', 'varchar(64)') = 'rpc_completed'
)x
Insert Into WaitInfo
Select
[timestamp], wait_type, wait_type_duration_ms, wait_type_signal_duration_ms, LEFT(Correlation,36) as 'Correlation',
REPLACE(RIGHT(Correlation,2),'-','') as 'Sequence',
datepart(Minute,timestamp) as [Minute],datepart(second,timestamp) as [Second],datepart(MILLISECOND,timestamp) as [Millisecond],@szenario
from (
SELECT n.value('(@timestamp)[1]', 'datetime2') AS [timestamp],
n.value('(data[@name="wait_type"]/text)[1]', 'varchar(25)') AS wait_type,
n.value('(data[@name="duration"]/value)[1]', 'int') AS wait_type_duration_ms,
n.value('(data[@name="signal_duration"]/value)[1]', 'int') AS wait_type_signal_duration_ms,
n.value('(action[@name="attach_activity_id"]/value)[1]', 'varchar(512)') AS Correlation
FROM
#capture_stpandwaits_data
CROSS APPLY event_data.nodes('event')as q(n)
where n.value('(@name)[1]', 'varchar(64)') = 'wait_info'
)x
end
GO
/****** Object: Table [dbo].[ProcedureExecutionTime] Script Date: 12/1/2015 4:02:16 PM ******/
CREATE TABLE [dbo].[ProcedureExecutionTime](
[timestamp] [datetime2](7) NULL,
[cpu_time] [int] NULL,
[duration_in_microseconds] [int] NULL,
[physical_reads] [int] NULL,
[logical_reads] [int] NULL,
[writes] [int] NULL,
[row_count] [int] NULL,
[SqlText] [nvarchar](512) NULL,
[Correlation] [uniqueidentifier] NULL,
[Sequence] [int] NULL,
[Minute] [int] NULL,
[Second] [int] NULL,
[Millisecond] [int] NULL,
[Szenario] [varchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[WaitInfo](
[timestamp] [datetime2](7) NULL,
[wait_type] [varchar](25) NULL,
[wait_type_duration_ms] [int] NULL,
[wait_type_signal_duration_ms] [int] NULL,
[Correlation] [uniqueidentifier] NULL,
[Sequence] [int] NULL,
[Minute] [int] NULL,
[Second] [int] NULL,
[Millisecond] [int] NULL,
[Szenario] [varchar](50) NULL
) ON [PRIMARY]
--Run the trace for the duration specified:
use [PowerBITrace]
exec [StpandWaitTrace] '00:00:10', 'Trace3'
-- Use power bi to analyze the storedprocedures and the waits now.
--Use these two statements:
Select * from PowerBITrace.dbo.ProcedureExecutionTime
Select * from PowerBITrace.dbo.WaitInfo
---Important don’t forget that it will only trace your RPC Calls! so to test the script you could use the following C# Program:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PowerBITraceDemo
{
class Program
{
static void Main(string[] args)
{
SqlConnection conn = new SqlConnection("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=AdventureWorks;Data Source=.\\SQL2014");
SqlCommand cmd = new SqlCommand("test", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
}
It might happen that the rpc trace returns multiple rows with the same correlation id. in this case you have to run the following cleanup step:
Delete from ProcedureExecutionTime where Correlation in (
Select Correlation from ProcedureExecutionTime group by Correlation having COUNT(*) > 1)