sqlServer 检测慢 sql

部署监控:
部署慢SQL与死锁跟踪
Skip to end of metadata
仅SQL Server 2012及以上版本可用.
执行前请确保路径正确!
慢SQL定义:执行时间超过0.5秒即定义为慢SQL,会被捕获。
SSMS中新建查询窗口,将下面代码贴上后执行。
该代码会新建一个[YX_Monitor]库,库中包含[DeadlockDetail]、[SlowSqlDetail]、[SlowSqlReadLog]、[BlockDetail]四个表
DeadlockDetail:死锁明细记录数据,可查看死锁相关信息。
SlowSqlDetail:慢SQL明细数据,可查看所有慢SQL的执行情况。
SlowSqlReadLog:监控读取记录表,仅用于监控识别数据读取。
BlockDetail:记录阻塞信息。

用前必读:
脚本初始部分有一段注释,这个注释中的内容是通过打开SQL Server的CMD调用开关,调用CMD命令来创建保存跟踪文件的文件夹。此命令通常用于我们无法远程上服务器本机创建文件夹路径时使用。
如果需要使用,请在打开开关时注意[show advanced options] 与[xp_cmdshell]开关的状态,0为关闭,1为开启。使用后请恢复原位。

-----------------------------------------------------------------------------------------
------------执行前请确保路径 D:\TraceFile  存在,如要更改路径请先更改后再执行------------
-----------------------------------------------------------------------------------------
/***
如不能远程到服务器,使用xp_cmdshell创建文件夹路径
-- 开启
exec sp_configure 'show advanced options',1
go
reconfigure with override
go
exec sp_configure 'xp_cmdshell',1
go
reconfigure with override
go
       
exec sys.xp_cmdshell 'dir D:\TraceFile' --查看文件夹
exec sys.xp_cmdshell 'mkdir D:\TraceFile' --新建文件夹
exec sys.xp_cmdshell 'rd D:\TraceFile' --删除文件夹
       
--关闭
exec sp_configure 'xp_cmdshell',0
go
reconfigure with override
go
exec sp_configure 'show advanced options',0
go
reconfigure with override
go
       
***/
----0.阻塞阈值设定
exec sp_configure 'show advanced options',1
reconfigure with override
go
exec sp_configure 'xp_cmdshell',1
reconfigure with override
go
EXEC sys.sp_configure N'blocked process threshold (s)', N'5'
reconfigure with override
GO
exec sp_configure 'xp_cmdshell',0
reconfigure with override
go
exec sp_configure 'show advanced options',0
reconfigure with override
go
    
----1.建库
use master
go
if(select name from sys.databases where name='YX_Monitor') is null
begin
    CREATE DATABASE YX_Monitor
       
       
    ALTER DATABASE [YX_Monitor] MODIFY FILE ( NAME = N'YX_Monitor', SIZE = 65536KB , FILEGROWTH = 65536KB )
    ALTER DATABASE [YX_Monitor] MODIFY FILE ( NAME = N'YX_Monitor_log', SIZE = 65536KB , FILEGROWTH = 65536KB )
end
go
       
----2.建表
use YX_Monitor
go
       
if object_id('YX_Monitor.dbo.SlowSqlReadLog') is null
BEGIN
    CREATE TABLE [dbo].[SlowSqlReadLog](
        [TransactionNumber] [bigint] IDENTITY(1,1) NOT NULL,
        [LogServer] [nvarchar](100) NULL,
        [LogTime] [datetime] NULL CONSTRAINT [DF_SlowSqlReadLog_LogTime]  DEFAULT (getdate()),
        [Last_Event_Time] [datetime2](7) NULL,
    CONSTRAINT [PK_SlowSqlReadLog] PRIMARY KEY CLUSTERED
    (
        [TransactionNumber] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
end
       
       
if object_id('YX_Monitor.dbo.SlowSqlDetail') is null
BEGIN
           
    CREATE TABLE [dbo].[SlowSqlDetail](
        [TransactionNumber] [bigint] NULL,
        [LogServer] [nvarchar](100) NULL,
        [EventTime] [datetime2](7) NULL,
        [EventName] [nvarchar](128) NULL,
        [statement] [nvarchar](max) NULL,
        [Sql_Text] [nvarchar](max) NULL,
        [Cpu] [bigint] NULL,
        [Logical_Reads] [bigint] NULL,
        [Physical_reads] [bigint] NULL,
        [Writes] [bigint] NULL,
        [Duration_ms] [bigint] NULL,
        [username] [nvarchar](128) NULL,
        [DatabaseName] [nvarchar](128) NULL,
        [ClientHostName] [nvarchar](128) NULL,
        [ClientAppName] [nvarchar](128) NULL,
        [SessionId] [int] NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
       
    create clustered index CIX_SlowSqlDetail_TransactionNumber on SlowSqlDetail(TransactionNumber,EventTime)
end
       
if object_id('yx_monitor.dbo.DeadlockDetail') is null
begin
    CREATE TABLE [dbo].[DeadlockDetail](
        [EventTime] [datetime2](7) NULL,
        [LogServer] [varchar](30) NULL,
        [InputBuffer] [nvarchar](max) NULL,
        [lockMode] [varchar](10) NULL,
        [spid] [int] NULL,
        [hostname] [varchar](50) NULL,
        [clientapp] [varchar](100) NULL,
        [transactionname] [varchar](50) NULL,
        [status] [varchar](20) NULL,
        [waitresource] [varchar](200) NULL
    )
       
    create clustered index CIX_DeadlockDetail_EventTime on DeadlockDetail([EventTime],[LogServer])
end
       
     
if object_id('YX_Monitor.dbo.BlockedDetail') is null
BEGIN
           
    create table BlockedDetail(
        EventTime datetime2,
        LogServer varchar(30),
        SPID int,
        Process_Type varchar(10),
        [Status] varchar(20),
        BlockedTime_ms bigint,
        LockMode varchar(10),
        WaitResource varchar(100),
        InputBuffer nvarchar(max),
        ClientApp varchar(100),
        HostName varchar(50)
    )
       
    create clustered index CIX_BlockedDetail_EventTime on BlockedDetail(EventTime)
end
     
go
       
       
----3.扩展事件慢SQL会话
DECLARE @sessionName NVARCHAR(100),@createAndBegin BIT,@fileLocation NVARCHAR(100),@sql NVARCHAR(max)
    ,@cpuFilter NVARCHAR(100),@durationFilter_s decimal(4,2),@durationFilter_us NVARCHAR(100),@maxSizeMB NVARCHAR(10),@rolloverNum NVARCHAR(10)
    ,@rpc_completed TINYINT,@sp_statement_completed TINYINT,@sql_batch_completed TINYINT,@sql_statement_completed TINYINT
       
       
SELECT @sessionName=N'DB_SlowSql'
    ,@fileLocation=N'D:\TraceFile\'+@sessionName+'.xel'
    ,@cpuFilter=1000
    ,@durationFilter_s=0.5
    ,@maxSizeMB=3
    ,@rolloverNum=1
    ,@createAndBegin=1
    ,@rpc_completed=1
    ,@sp_statement_completed=0
    ,@sql_batch_completed=1
    ,@sql_statement_completed=0
    ,@durationFilter_us=cast(@durationFilter_s*1000*1000 as int)
       
IF(@rpc_completed+@sp_statement_completed+@sql_batch_completed+@sql_statement_completed)=0
BEGIN
    RAISERROR('至少选择一种跟踪事件!',16,3)
    RETURN
END
       
IF exists(SELECT * FROM sys.server_event_sessions WHERE name=@SessionName)
BEGIN
    RAISERROR('警告:扩展事件会话 %s 已存在,无法创建重命名会话!该步骤已跳过!',10,1,@SessionName)
    RETURN
END
ELSE
BEGIN
       
SET @sql=N'
CREATE EVENT SESSION ['+@SessionName+'] ON SERVER
'
       
IF(@rpc_completed=1)
BEGIN
    SET @sql=@sql+'ADD EVENT sqlserver.rpc_completed(
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.request_id
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username)
    WHERE ([cpu_time]>='+@cpuFilter+' and duration>='+@durationFilter_us+')),'
END
IF(@sp_statement_completed=1)
BEGIN
    SET @sql=@sql+'ADD EVENT sqlserver.sp_statement_completed(
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.request_id
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username)
    WHERE ([cpu_time]>='+@cpuFilter+' and duration>='+@durationFilter_us+')),'
END
IF(@sql_batch_completed=1)
BEGIN
    SET @sql=@sql+'ADD EVENT sqlserver.sql_batch_completed(SET collect_batch_text=(1)
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.request_id
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username)
    WHERE ([cpu_time]>='+@cpuFilter+' and duration>='+@durationFilter_us+')),'
END
IF(@sql_statement_completed=1)
BEGIN
    SET @sql=@sql+'ADD EVENT sqlserver.sql_statement_completed (
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.request_id
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username)
    WHERE ([cpu_time]>='+@cpuFilter+' and duration>='+@durationFilter_us+')),'
END
       
--去除最后的逗号
SELECT @sql=left(@sql,LEN(@sql)-1)
       
SET @sql=@sql+'ADD TARGET package0.event_file(SET filename=N'''+@fileLocation+''',max_file_size=('+@maxSizeMB+'),max_rollover_files=('+@rolloverNum+'))'
set @sql=@sql+'WITH (MAX_MEMORY=8192 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_NODE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)'
       
       
IF(@CreateAndBegin=1)
    SELECT @sql=@sql+'
ALTER EVENT SESSION ['+@SessionName+'] ON SERVER STATE = start;'
       
PRINT @sql
EXEC(@sql)
       
end
       
GO
       
       
----4.扩展事件死锁会话
DECLARE @sessionName NVARCHAR(100),@createAndBegin BIT,@fileLocation NVARCHAR(100),@sql NVARCHAR(max)
    ,@maxSizeMB NVARCHAR(10),@rolloverNum NVARCHAR(10)
           
SELECT @sessionName=N'DB_Deadlock'
    ,@fileLocation=N'D:\TraceFile\'+@sessionName+'.xel'
    ,@maxSizeMB=3
    ,@rolloverNum=1
    ,@createAndBegin=1
       
       
       
IF exists(SELECT * FROM sys.server_event_sessions WHERE name=@SessionName)
BEGIN
    RAISERROR('警告:扩展事件会话 %s 已存在,无法创建重命名会话!该步骤已跳过!',10,1,@SessionName)
    RETURN
END
ELSE
BEGIN
       
SET @sql=N'
CREATE EVENT SESSION ['+@SessionName+'] ON SERVER
'
       
SET @sql=@sql+'ADD EVENT sqlserver.xml_deadlock_report(
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.request_id
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username))
'
SET @sql=@sql+'ADD TARGET package0.event_file(SET filename=N'''+@fileLocation+''',max_file_size=('+@maxSizeMB+'),max_rollover_files=('+@rolloverNum+'))'
set @sql=@sql+'WITH (MAX_MEMORY=8192 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_NODE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)'
       
       
IF(@CreateAndBegin=1)
    SELECT @sql=@sql+'
ALTER EVENT SESSION ['+@SessionName+'] ON SERVER STATE = start;'
       
PRINT @sql
EXEC(@sql)
       
end
GO
     
     
----5.扩展事件阻塞会话
DECLARE @sessionName NVARCHAR(100),@createAndBegin BIT,@fileLocation NVARCHAR(100),@sql NVARCHAR(max)
    ,@maxSizeMB NVARCHAR(10),@rolloverNum NVARCHAR(10)
           
SELECT @sessionName=N'DB_Blocked'
    ,@fileLocation=N'D:\TraceFile\'+@sessionName+'.xel'
    ,@maxSizeMB=3
    ,@rolloverNum=1
    ,@createAndBegin=1
     
IF exists(SELECT * FROM sys.server_event_sessions WHERE name=@SessionName)
BEGIN
    RAISERROR('警告:扩展事件会话 %s 已存在,无法创建重命名会话!该步骤已跳过!',10,1,@SessionName)
    RETURN
END
ELSE
BEGIN
       
SET @sql=N'
CREATE EVENT SESSION ['+@SessionName+'] ON SERVER
'
       
SET @sql=@sql+'ADD EVENT sqlserver.blocked_process_report(
    ACTION(sqlserver.client_app_name
    ,sqlserver.client_hostname
    ,sqlserver.database_id
    ,sqlserver.database_name
    ,sqlserver.session_id
    ,sqlserver.sql_text
    ,sqlserver.username))
'
SET @sql=@sql+'ADD TARGET package0.event_file(SET filename=N'''+@fileLocation+''',max_file_size=('+@maxSizeMB+'),max_rollover_files=('+@rolloverNum+'))'
set @sql=@sql+'WITH (MAX_MEMORY=8192 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_NODE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)'
       
       
IF(@CreateAndBegin=1)
    SELECT @sql=@sql+'
ALTER EVENT SESSION ['+@SessionName+'] ON SERVER STATE = start;'
       
PRINT @sql
EXEC(@sql)
       
end
GO
     
/***
新增CPU利用率记录
***/
use YX_Monitor
go
if OBJECT_ID('CpuUsage') is not null
drop table CpuUsage
   
create table CpuUsage(
    EventTime varchar(16),
    SQLUsage int,
    OtherUsage int,
    TotalUsage int,
    SystemIdle int
)
       
CREATE CLUSTERED INDEX CIX_CpuUsage_EventTime on CpuUsage(EventTime)
go
   
----5.创建JOB -- 为确保作业正确,会删除老JOB然后新建JOB
USE [msdb]
GO
     
if(select count(1) from msdb.dbo.sysjobs where name='(每90秒) 读取监控文件')>0
begin
    declare @job_id uniqueidentifier
    select @job_id = job_id from msdb.dbo.sysjobs where name='(每90秒) 读取监控文件'
       
    EXEC msdb.dbo.sp_delete_job @job_id=@job_id, @delete_unused_schedule=1
end
go
     
/****** Object:  Job [(每90秒) 读取监控文件]    Script Date: 2022-11-14 9:12:44 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]    Script Date: 2022-11-14 9:12:44 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
   
END
   
DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'(每90秒) 读取监控文件',
        @enabled=1,
        @notify_level_eventlog=0,
        @notify_level_email=0,
        @notify_level_netsend=0,
        @notify_level_page=0,
        @delete_level=0,
        @description=N'(每90秒) 读取监控文件',
        @category_name=N'[Uncategorized (Local)]',
        @owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [slowsql]    Script Date: 2022-11-14 9:12:44 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'slowsql',
        @step_id=1,
        @cmdexec_success_code=0,
        @on_success_action=3,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'use YX_Monitor
go
--pepare data
declare @fileLocation nvarchar(128)
     
select @fileLocation=cast(esf.value as nvarchar(128)) from sys.server_event_sessions es
inner join sys.server_event_session_fields esf
on es.event_session_id=esf.event_session_id
where esf.name=''filename''
and es.name =''DB_SlowSql''
select @fileLocation=left(@fileLocation,LEN(@fileLocation)-4)+''*.xel''
     
set QUOTED_IDENTIFIER on
     
if object_id(''tempdb..#tmp'') is not null
    drop table #tmp
     
;WITH events_cte AS (
    SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), xevents.event_data.value(''(event/@timestamp)[1]'', ''datetime2'')) AS [EventTime]
        ,xevents.event_data.value(''(event/@name)[1]'', ''nvarchar(128)'') AS [EventName]
        , xevents.event_data.value(''(event/data[@name="statement"]/value)[1]'', ''nvarchar(max)'') AS [statement]
        , xevents.event_data.value(''(event/action[@name="sql_text"]/value)[1]'', ''nvarchar(max)'') AS [Sql_Text]
        , xevents.event_data.value(''(event/data[@name="cpu_time"]/value)[1]'', ''bigint'') / 1000 AS [CPU]
        , xevents.event_data.value(''(event/data[@name="logical_reads"]/value)[1]'', ''bigint'') AS [Logical_Reads]
        , xevents.event_data.value(''(event/data[@name="physical_reads"]/value)[1]'', ''bigint'') AS [Physical_reads]
        , xevents.event_data.value(''(event/data[@name="writes"]/value)[1]'', ''bigint'') AS [Writes]
        , xevents.event_data.value(''(event/data[@name="duration"]/value)[1]'', ''bigint'') / 1000 AS [Duration_ms]
        , xevents.event_data.value(''(event/action[@name="username"]/value)[1]'', ''nvarchar(128)'') AS [username]
        , xevents.event_data.value(''(event/action[@name="database_name"]/value)[1]'', ''nvarchar(128)'') AS [DatabaseName]
        , xevents.event_data.value(''(event/action[@name="client_hostname"]/value)[1]'', ''nvarchar(128)'') AS [ClientHostName]
        , xevents.event_data.value(''(event/action[@name="client_app_name"]/value)[1]'', ''nvarchar(128)'') AS [ClientAppName]
        , xevents.event_data.value(''(event/action[@name="session_id"]/value)[1]'', ''nvarchar(128)'') AS [SessionId]
    FROM sys.fn_xe_file_target_read_file( @fileLocation, NULL, NULL, NULL)
    CROSS APPLY ( SELECT CAST(event_data AS XML ) AS event_data) xevents
)
SELECT *
into #tmp
FROM events_cte
ORDER BY [EventTime] DESC;
     
     
declare @LogSrever nvarchar(128),@last_Event_Time datetime2,@transactionNumber bigint,@before_last_Event_Time datetime2
     
select @before_last_Event_Time=(select top 1 last_Event_Time
    from SlowSqlReadLog
    where LogServer=@@SERVERNAME
    order by LogTime desc)
     
select @LogSrever=@@SERVERNAME,@last_Event_Time=(select top 1 EventTime
    from #tmp
    ORDER BY [EventTime] DESC)
     
if (isnull(@before_last_Event_Time,'''')<@Last_event_time)
begin
    --SlowSqlReadLog
    insert into SlowSqlReadLog(LogServer,Last_event_time)
    select @LogSrever,@Last_event_time
     
    --SlowSqlDetail
    select @transactionNumber=SCOPE_IDENTITY()
     
    insert into SlowSqlDetail(
    TransactionNumber
    ,LogServer
    ,EventTime
    ,EventName
    ,statement
    ,Sql_Text
    ,Cpu
    ,Logical_Reads
    ,Physical_reads
    ,Writes
    ,Duration_ms
    ,username
    ,DatabaseName
    ,ClientHostName
    ,ClientAppName
    ,SessionId)
    select @transactionNumber
    ,@LogSrever
    ,EventTime
    ,EventName
    ,statement
    ,Sql_Text
    ,Cpu
    ,Logical_Reads
    ,Physical_reads
    ,Writes
    ,Duration_ms
    ,username
    ,DatabaseName
    ,ClientHostName
    ,ClientAppName
    ,SessionId
    from #tmp
    where EventTime between isnull(@before_last_Event_Time,'''') and @last_Event_Time
end
     
',
        @database_name=N'YX_Monitor',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [deadlock]    Script Date: 2022-11-14 9:12:44 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'deadlock',
        @step_id=2,
        @cmdexec_success_code=0,
        @on_success_action=3,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'use YX_Monitor
go
--pepare data
declare @fileLocation nvarchar(128)
     
select @fileLocation=cast(esf.value as nvarchar(128)) from sys.server_event_sessions es
inner join sys.server_event_session_fields esf
on es.event_session_id=esf.event_session_id
where esf.name=''filename''
and es.name =''DB_Deadlock''
select @fileLocation=left(@fileLocation,LEN(@fileLocation)-4)+''*.xel''
     
set QUOTED_IDENTIFIER on
     
if object_id(''tempdb..#tmpDeadLock'') is not null
    drop table #tmpDeadLock
     
select CAST(event_data AS XML ) AS event_data
into #tmpDeadLock
from  sys.fn_xe_file_target_read_file( @fileLocation, NULL, NULL, NULL)
     
--select * from #tmpDeadLock
     
declare @eventXML xml,@maxTime datetime2
     
select @maxTime=isnull(max(EventTime),'''')
from DeadlockDetail
     
DECLARE XML_Cursor CURSOR
LOCAL STATIC FORWARD_ONLY
READ_ONLY
FOR
SELECT event_data from #tmpDeadLock
OPEN XML_Cursor
FETCH NEXT FROM XML_Cursor INTO @eventXML
WHILE @@fetch_status = 0
BEGIN
    declare @process xml,@resource xml,@eventTime datetime2
     
    select @eventTime=DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), t1.c1.value(''@timestamp'', ''datetime2''))
    from @eventXML.nodes(''/event'') as T1(C1)
     
     
    if(@eventTime>@maxTime)
    begin
        select
        @process=t1.c1.query(''./process-list'')
        from @eventXML.nodes(''/event/data/value/deadlock'') as T1(C1)
     
        insert into DeadlockDetail
        select @eventTime AS [EventTime]
        ,@@SERVERNAME as [LogServer]
        ,T1.C1.value(''(./inputbuf)[1]'',''varchar(max)'') as inputbuffer
        ,T1.C1.value(''@lockMode'',''varchar(100)'') as lockMode
        ,T1.C1.value(''@spid'',''varchar(100)'') as spid
        ,T1.C1.value(''@hostname'',''varchar(100)'') as hostname
        ,T1.C1.value(''@clientapp'',''varchar(100)'') as clientapp
        ,T1.C1.value(''@transactionname'',''varchar(100)'') as transactionname
        ,T1.C1.value(''@status'',''varchar(100)'') as status
        ,T1.C1.value(''@waitresource'',''varchar(100)'') as waitresource
        from @process.nodes(''/process-list/process'') as T1(C1)
    end
     
    FETCH NEXT FROM XML_Cursor INTO @eventXML
END
CLOSE XML_Cursor
DEALLOCATE XML_Cursor
     
',
        @database_name=N'YX_Monitor',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [blocked]    Script Date: 2022-11-14 9:12:44 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'blocked',
        @step_id=3,
        @cmdexec_success_code=0,
        @on_success_action=3,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'use YX_Monitor
go
--pepare data
declare @fileLocation nvarchar(128)
     
select @fileLocation=cast(esf.value as nvarchar(128)) from sys.server_event_sessions es
inner join sys.server_event_session_fields esf
on es.event_session_id=esf.event_session_id
where esf.name=''filename''
and es.name =''DB_Blocked''
select @fileLocation=left(@fileLocation,LEN(@fileLocation)-4)+''*.xel''
     
set QUOTED_IDENTIFIER on
     
if object_id(''tempdb..#tmpBlocked'') is not null
    drop table #tmpBlocked
     
select CAST(event_data AS XML ) AS event_data
into #tmpBlocked
from  sys.fn_xe_file_target_read_file( @fileLocation, NULL, NULL, NULL)
     
--select * from #tmpBlocked
     
declare @eventXML xml,@maxTime datetime2
     
select @maxTime=isnull(max(EventTime),'''')
from BlockedDetail
     
DECLARE XML_Cursor CURSOR
LOCAL STATIC FORWARD_ONLY
READ_ONLY
FOR
SELECT event_data from #tmpBlocked
OPEN XML_Cursor
FETCH NEXT FROM XML_Cursor INTO @eventXML
WHILE @@fetch_status = 0
BEGIN
    declare @blocked xml,@blocking xml,@resource xml,@eventTime datetime2,@duration_ms bigint
     
    select @eventTime=DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), t1.c1.value(''@timestamp'', ''datetime2''))
    from @eventXML.nodes(''/event'') as T1(C1)
     
    select @duration_ms= t1.c1.value(''(./value)[1]'',''bigint'')
    from @eventXML.nodes(''/event/data[@name="duration"]'') as T1(C1)
     
    if(@eventTime>@maxTime)
    begin
        select
        @blocked=t1.c1.query(''blocked-process'')
        from @eventXML.nodes(''/event/data[@name="blocked_process"]/value/blocked-process-report'') as T1(C1)
     
        select
        @blocking=t1.c1.query(''blocking-process'')
        from @eventXML.nodes(''/event/data[@name="blocked_process"]/value/blocked-process-report'') as T1(C1)
     
        insert into BlockedDetail
        select @eventTime as EventTime
        ,@@SERVERNAME as [LogServer]
        ,T1.C1.value(''@spid'',''varchar(100)'') as spid
        ,''blocked'' AS PROCESS_TYPE
        ,T1.C1.value(''@status'',''varchar(100)'') as status
        ,@duration_ms/1000 as BlockedTime_ms
        ,T1.C1.value(''@lockMode'',''varchar(100)'') as lockMode
        ,T1.C1.value(''@waitresource'',''varchar(100)'') as waitresource
        ,T1.C1.value(''(./inputbuf)[1]'',''varchar(max)'') as inputbuffer
        ,T1.C1.value(''@clientapp'',''varchar(100)'') as clientapp
        ,T1.C1.value(''@hostname'',''varchar(100)'') as hostname
        from @blocked.nodes(''/blocked-process/process'') as T1(C1)
        union all
        select @eventTime as EventTime
        ,@@SERVERNAME as [LogServer]
        ,T1.C1.value(''@spid'',''varchar(100)'') as spid
        ,''blocking'' AS PROCESS_TYPE
        ,T1.C1.value(''@status'',''varchar(100)'') as status
        ,@duration_ms/1000 as BlockedTime_ms
        ,T1.C1.value(''@lockMode'',''varchar(100)'') as lockMode
        ,T1.C1.value(''@waitresource'',''varchar(100)'') as waitresource
        ,T1.C1.value(''(./inputbuf)[1]'',''varchar(max)'') as inputbuffer
        ,T1.C1.value(''@clientapp'',''varchar(100)'') as clientapp
        ,T1.C1.value(''@hostname'',''varchar(100)'') as hostname
        from @blocking.nodes(''/blocking-process/process'') as T1(C1)
    end
    FETCH NEXT FROM XML_Cursor INTO @eventXML
END
CLOSE XML_Cursor
DEALLOCATE XML_Cursor
     
',
        @database_name=N'master',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [cpuusage]    Script Date: 2022-11-14 9:12:44 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'cpuusage',
        @step_id=4,
        @cmdexec_success_code=0,
        @on_success_action=3,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'set QUOTED_IDENTIFIER on
DECLARE @ts_now BIGINT;
SET  @ts_now= ( SELECT  cpu_ticks / ( cpu_ticks / ms_ticks ) FROM sys.dm_os_sys_info WITH ( NOLOCK ));
    
    
MERGE INTO YX_Monitor.dbo.CpuUsage a
USING
(
SELECT convert(varchar(16),DATEADD(ms, -1*(@ts_now-[timestamp]), GETDATE()),120) AS EventTime
    ,SQLProcessUtilization                                  AS SQLUsage
    ,100 - SystemIdle - SQLProcessUtilization               AS OtherUsage
    ,100 - SystemIdle                                       AS TotalUsage
    ,SystemIdle                                             AS SystemIdle
 FROM   (
    SELECT    record.value(''(./Record/@id)[1]'', ''int'') AS record_id ,
    record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]'',''int'') AS [SystemIdle] ,
    record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]'',''int'') AS [SQLProcessUtilization] ,
    [timestamp]
    FROM(
        SELECT    [timestamp] ,
        CONVERT(XML, record) AS [record]
        FROM      sys.dm_os_ring_buffers WITH ( NOLOCK )
        WHERE     ring_buffer_type = N''RING_BUFFER_SCHEDULER_MONITOR''
        AND record LIKE N''%%''
    ) AS x
) AS y
)  b
    
ON ( a.EventTime=b.EventTime)
WHEN NOT MATCHED THEN
INSERT (EventTime,SQLUsage,OtherUsage,TotalUsage,SystemIdle) VALUES(b.EventTime,b.SQLUsage,b.OtherUsage,b.TotalUsage,b.SystemIdle);
   
   
',
        @database_name=N'master',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [clearHistory]    Script Date: 2022-11-14 9:12:44 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'clearHistory',
        @step_id=5,
        @cmdexec_success_code=0,
        @on_success_action=1,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'delete YX_Monitor.dbo.SlowSqlDetail
where eventtime 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'1',
        @enabled=1,
        @freq_type=4,
        @freq_interval=1,
        @freq_subday_type=2,
        @freq_subday_interval=90,
        @freq_relative_interval=0,
        @freq_recurrence_factor=0,
        @active_start_date=20220101,
        @active_end_date=99991231,
        @active_start_time=0,
        @active_end_time=235959,
        @schedule_uid=N'a53b9137-2256-4675-b5d1-fa13902cdc4f'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
   
   
   
    
    
/****
以下部分为慢SQL汇总统计部分
****/
use YX_Monitor
go
if object_id('SlowSqlExecLine') is not null
    drop table SlowSqlExecLine
    
create table SlowSqlExecLine(
    EventDate date,
    ClientAppName varchar(128),
    TotalCounts int,
    Line50 int,
    Line95 int
)
    
create clustered index CIX_SlowSqlExecLine_EventDate_ClientAppName on SlowSqlExecLine(EventDate,ClientAppName)
go
    
if object_id('SlowSqlExecTime') is not null
    drop table SlowSqlExecTime
    
create table SlowSqlExecTime(
    EventDate date,
    ClientAppName varchar(128),
    Counts int,
    [0_1sec] int,
    [1_2sec] int,
    [2_5sec] int,
    [5_10sec] int,
    [10+s] int
)
create clustered index CIX_SlowSqlExecTime_EventDate_ClientAppName on SlowSqlExecTime(EventDate,ClientAppName)
go
    
    
        
----创建JOB -- 为确保作业正确,会删除老JOB然后新建JOB
USE [msdb]
GO
      
if(select count(1) from msdb.dbo.sysjobs where name='(02:00)统计前一天的慢SQL')>0
begin
    declare @job_id uniqueidentifier
    select @job_id = job_id from msdb.dbo.sysjobs where name='(02:00)统计前一天的慢SQL'
        
    EXEC msdb.dbo.sp_delete_job @job_id=@job_id, @delete_unused_schedule=1
end
go
    
USE [msdb]
GO
    
/****** Object:  Job [(02:00)统计前一天的慢SQL]    Script Date: 2022-11-12 16:56:29 ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]    Script Date: 2022-11-12 16:56:29 ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
    
END
    
DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'(02:00)统计前一天的慢SQL',
        @enabled=1,
        @notify_level_eventlog=0,
        @notify_level_email=0,
        @notify_level_netsend=0,
        @notify_level_page=0,
        @delete_level=0,
        @description=N'无描述。',
        @category_name=N'[Uncategorized (Local)]',
        @owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [1_execline]    Script Date: 2022-11-12 16:56:29 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'1_execline',
        @step_id=1,
        @cmdexec_success_code=0,
        @on_success_action=3,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'declare @today date=getdate()-1
    
    
insert into yx_monitor.dbo.SlowSqlExecLine
SELECT distinct @today,ClientAppName,count(1) OVER (PARTITION BY ClientAppName) as TotalCounts
,PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY Duration_ms)
OVER (PARTITION BY ClientAppName) AS Line50
,PERCENTILE_DISC(0.95) WITHIN GROUP (ORDER BY Duration_ms)
OVER (PARTITION BY ClientAppName) AS Line95
FROM (select (case
    when ClientAppName like ''%系统%'' then substring(ClientAppName,0,charindex(''系统'',clientappname)+2)
    when ClientAppName like ''%[[]%'' then substring(ClientAppName,0,charindex(''['',clientappname))
    else ClientAppName end) as ClientAppName,Duration_ms
from yx_monitor.dbo.SlowSqlDetail
where ClientAppName not like ''%SQLAgent%'' and EventTime between @today and dateadd(day,1,@today)
)x
order by TotalCounts desc',
        @database_name=N'master',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [2_exectime]    Script Date: 2022-11-12 16:56:29 ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'2_exectime',
        @step_id=2,
        @cmdexec_success_code=0,
        @on_success_action=1,
        @on_success_step_id=0,
        @on_fail_action=2,
        @on_fail_step_id=0,
        @retry_attempts=0,
        @retry_interval=0,
        @os_run_priority=0, @subsystem=N'TSQL',
        @command=N'declare @day date=getdate()-1
    
    
insert into YX_Monitor.dbo.SlowSqlExecTime
    
select @day,ClientAppName,count(1) as Counts
,sum(case when duration_ms<=1000 then 1 else 0 end) as ''0_1sec''
,sum(case when duration_ms > 1000 and duration_ms<=2000 then 1 else 0 end) as ''1_2sec''
,sum(case when duration_ms > 2000 and duration_ms<=5000 then 1 else 0 end) as ''2_5sec''
,sum(case when duration_ms > 5000 and duration_ms<=10000 then 1 else 0 end) as ''5_10sec''
,sum(case when duration_ms >10000 then 1 else 0 end) as ''10+s''
from (
select (case
    when ClientAppName like ''%系统%'' then substring(ClientAppName,0,charindex(''系统'',clientappname)+2)
    when ClientAppName like ''%[[]%'' then substring(ClientAppName,0,charindex(''['',clientappname))
    else ClientAppName end) as ClientAppName,Duration_ms
from YX_Monitor.dbo.SlowSqlDetail
where ClientAppName not like ''%SQLAgent%'' and EventTime between @day and dateadd(day,1,@day)
) x
group by ClientAppName
order by counts desc',
        @database_name=N'master',
        @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'0200',
        @enabled=1,
        @freq_type=4,
        @freq_interval=1,
        @freq_subday_type=1,
        @freq_subday_interval=0,
        @freq_relative_interval=0,
        @freq_recurrence_factor=0,
        @active_start_date=20221112,
        @active_end_date=99991231,
        @active_start_time=20000,
        @active_end_time=235959,
        @schedule_uid=N'9dad6154-a685-4f52-9da4-539b232135db'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

例:
[show advanced options] 原始状态为1(开)
[xp_cmdshell]原始状态为0(关)
使用完毕后,关闭[xp_cmdshell],不关闭[show advanced options]。

sqlServer 实时 检测慢 sql

WITH sess AS
(
  SELECT
  es.session_id,
  database_name = DB_NAME(er.database_id),
  er.cpu_time,
  er.reads,
  er.writes,
  er.logical_reads,
  login_name,
  er.status,
  blocking_session_id,
  wait_type,
  wait_resource,
  wait_time,
  individual_query = SUBSTRING (qt.text, (er.statement_start_offset/2)+1, ((CASE WHEN er.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE er.statement_end_offset END - er.statement_start_offset)/2)+1),
  parent_query = qt.text,
  program_name,
  host_name,
  nt_domain,
  start_time,
  --DATEDIFF(MS,er.start_time,GETDATE()) as duration,
  (SELECT query_plan FROM sys.dm_exec_query_plan(er.plan_handle)) AS query_plan
  FROM
  sys.dm_exec_requests er
  INNER JOIN sys.dm_exec_sessions es ON er.session_id = es.session_id
  CROSS APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
  WHERE
  es.session_id > 50
  AND es.session_Id NOT IN (@@SPID)
)
SELECT
  *
FROM
  sess
UNION ALL SELECT
  es.session_id,
  database_name = '',
  0,
  0,
  0,
  0,
  login_name,
  es.status,
  0,
  '',
  '',
  '',
  qt.text,
  parent_query = qt.text,
  program_name,
  host_name,
  nt_domain,
  es.last_request_start_time,
  --DATEDIFF(MS,es.last_request_start_time,GETDATE()) as duration,
  NULL AS query_plan
FROM
  sys.dm_exec_sessions es
  INNER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
  CROSS APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle)as qt
WHERE
  ec.most_recent_session_id IN
  (
  SELECT blocking_session_id FROM sess WHERE blocking_session_id NOT IN(SELECT DISTINCT session_id FROM sess)
  )
ORDER BY
  cpu_time desc


  --实时查看依赖锁关系--

90秒,获取慢sql。

/****** SSMS 的 SelectTopNRows 命令的脚本  ******/
SELECT TOP (5000) [EventTime]
      ,[SPID]
      ,[Process_Type]
      ,[Status]
      ,[BlockedTime_ms]
      ,[LockMode]
      ,[WaitResource]
      ,[InputBuffer]
      ,[ClientApp]
      ,[HostName]
  FROM [YX_Monitor].[dbo].[BlockedDetail]
  order by eventtime desc


  ----  90秒记录一次慢SQL ----

你可能感兴趣的:(sql,sqlserver,sql,数据库)