Quantcast
Channel: MSDN Blogs
Viewing all articles
Browse latest Browse all 12366

Use Power BI to trace SQL Server RPC Calls and correlate them with Wait_info

$
0
0

 

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)


Viewing all articles
Browse latest Browse all 12366

Trending Articles