部署监控:
部署慢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 ----