250 lines
9.8 KiB
Transact-SQL
250 lines
9.8 KiB
Transact-SQL
--=========================================--
|
|
/*** SQL SERVER CPU MONITORING QUERIES ***/
|
|
--=========================================------
|
|
-- Supported Versions SQL server 2008 and higher
|
|
-------------------------------------------------
|
|
|
|
-------------------------------------
|
|
/*** 1. Current CPU Utilization ***/
|
|
-------------------------------------
|
|
|
|
DECLARE @ts BIGINT;
|
|
DECLARE @lastNmin TINYINT;
|
|
|
|
SELECT @ts = (SELECT cpu_ticks / ( cpu_ticks / ms_ticks )
|
|
FROM sys.dm_os_sys_info);
|
|
|
|
SELECT TOP(1) Dateadd(ms, -1 * ( @ts - [timestamp] ), Getdate())AS [EventTime],
|
|
sqlprocessutilization AS
|
|
[SQL Server Utilization],
|
|
100 - systemidle - sqlprocessutilization AS
|
|
[Other Process CPU_Utilization],
|
|
systemidle AS [System Idle]
|
|
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
|
|
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
|
|
AND record LIKE'%%')AS x)AS y
|
|
ORDER BY record_id DESC;
|
|
|
|
|
|
---------------------------------------------
|
|
/*** 2.CPU Utilization for last N minutes***/
|
|
---------------------------------------------
|
|
-- Mention the minutes in @lastNmin Parameter
|
|
|
|
DECLARE @ts BIGINT;
|
|
DECLARE @lastNmin TINYINT;
|
|
|
|
SET @lastNmin = 15; --Mention the Minutes Here
|
|
|
|
SELECT @ts = (SELECT cpu_ticks / ( cpu_ticks / ms_ticks )
|
|
FROM sys.dm_os_sys_info);
|
|
|
|
SELECT TOP(@lastNmin) Dateadd(ms, -1 * ( @ts - [timestamp] ), Getdate())AS
|
|
[EventTime],
|
|
sqlprocessutilization AS
|
|
[SQL Server Utilization],
|
|
100 - systemidle - sqlprocessutilization AS
|
|
[Other Process CPU_Utilization],
|
|
systemidle AS
|
|
[System Idle]
|
|
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
|
|
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
|
|
AND record LIKE'%%')AS x)AS y
|
|
ORDER BY record_id DESC;
|
|
|
|
|
|
------------------------------------------
|
|
/*** 3.Database wise CPU Utilization ***/
|
|
------------------------------------------
|
|
|
|
WITH db_cpu
|
|
AS (SELECT databaseid,
|
|
Db_name(databaseid) AS [DatabaseName],
|
|
Sum(total_worker_time)AS [CPU_Time(Ms)]
|
|
FROM sys.dm_exec_query_stats AS qs
|
|
CROSS apply(SELECT CONVERT(INT, value)AS [DatabaseID]
|
|
FROM sys.Dm_exec_plan_attributes(qs.plan_handle)
|
|
WHERE attribute = N'dbid')AS epa
|
|
GROUP BY databaseid)
|
|
SELECT Row_number()
|
|
OVER(
|
|
ORDER BY [cpu_time(ms)] DESC) AS [SNO],
|
|
databasename AS [DBName]
|
|
,
|
|
[cpu_time(ms)],
|
|
Cast([cpu_time(ms)] * 1.0 / Sum([cpu_time(ms)])
|
|
OVER() * 100.0 AS DECIMAL(5, 2))AS
|
|
[CPUPercent]
|
|
FROM db_cpu
|
|
WHERE databaseid > 4 -- system databases
|
|
AND databaseid <> 32767 -- ResourceDB
|
|
ORDER BY sno
|
|
OPTION(recompile);
|
|
|
|
|
|
---------------------------------------
|
|
/*** 4.Query Wise CPU Utilization ***/
|
|
---------------------------------------
|
|
-- This Query will show the queries and its CPU time if the avg CPU usgae is > 50
|
|
-- You can modify this in IF @AvgCPUUtilization >= 50
|
|
|
|
SET nocount ON
|
|
|
|
DECLARE @ts_now BIGINT
|
|
DECLARE @AvgCPUUtilization DECIMAL(10, 2)
|
|
|
|
SELECT @ts_now = cpu_ticks / ( cpu_ticks / ms_ticks )
|
|
FROM sys.dm_os_sys_info
|
|
|
|
-- load the CPU utilization in the past 10 minutes into the temp table, you can load them into a permanent table
|
|
SELECT TOP(10) sqlprocessutilization AS
|
|
[SQLServerProcessCPUUtilization],
|
|
systemidle AS
|
|
[SystemIdleProcess],
|
|
100 - systemidle - sqlprocessutilization AS
|
|
[OtherProcessCPU Utilization],
|
|
Dateadd(ms, -1 * ( @ts_now - [timestamp] ), Getdate()) AS
|
|
[EventTime]
|
|
INTO #cpuutilization
|
|
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
|
|
WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
|
|
AND record LIKE '%<SystemHealth>%') AS x) AS y
|
|
ORDER BY record_id DESC
|
|
|
|
-- check if the average CPU utilization was over 50% in the past 10 minutes
|
|
|
|
SELECT @AvgCPUUtilization = Avg([sqlserverprocesscpuutilization]
|
|
+ [otherprocesscpu utilization])
|
|
FROM #cpuutilization
|
|
WHERE eventtime > Dateadd(mm, -10, Getdate())
|
|
|
|
IF @AvgCPUUtilization >= 50
|
|
BEGIN
|
|
SELECT TOP(10) CONVERT(VARCHAR(25), @AvgCPUUtilization)
|
|
+ '%' AS
|
|
[AvgCPUUtilization],
|
|
Getdate()
|
|
[Date and Time]
|
|
,
|
|
r.cpu_time,
|
|
r.total_elapsed_time,
|
|
s.session_id,
|
|
s.login_name,
|
|
s.host_name,
|
|
Db_name(r.database_id) AS
|
|
DatabaseName
|
|
,
|
|
Substring (t.text, ( r.statement_start_offset / 2 ) + 1, (
|
|
( CASE
|
|
WHEN r.statement_end_offset = -1 THEN
|
|
Len(CONVERT(NVARCHAR(max), t.text)) *
|
|
2
|
|
ELSE r.statement_end_offset
|
|
END - r.statement_start_offset ) / 2 ) + 1) AS
|
|
[IndividualQuery],
|
|
Substring(text, 1, 200) AS [ParentQuery],
|
|
r.status,
|
|
r.start_time,
|
|
r.wait_type,
|
|
s.program_name
|
|
INTO #possiblecpuutilizationqueries
|
|
FROM sys.dm_exec_sessions s
|
|
INNER JOIN sys.dm_exec_connections c
|
|
ON s.session_id = c.session_id
|
|
INNER JOIN sys.dm_exec_requests r
|
|
ON c.connection_id = r.connection_id
|
|
CROSS apply sys.Dm_exec_sql_text(r.sql_handle) t
|
|
WHERE s.session_id > 50
|
|
AND r.session_id != @@spid
|
|
ORDER BY r.cpu_time DESC
|
|
|
|
|
|
SELECT *
|
|
FROM #possiblecpuutilizationqueries
|
|
END
|
|
|
|
-- drop the temp tables
|
|
IF Object_id('TEMPDB..#CPUUtilization') IS NOT NULL
|
|
DROP TABLE #cpuutilization
|
|
|
|
IF Object_id('TEMPDB..#PossibleCPUUtilizationQueries') IS NOT NULL
|
|
DROP TABLE #possiblecpuutilizationqueries
|
|
|
|
|
|
---------------------------------
|
|
/*** 5.TOP costliest Queries ***/
|
|
---------------------------------
|
|
-- This will give top 20 costliest queries which are executed recently.
|
|
|
|
SELECT TOP (20) st.text AS Query,
|
|
qs.execution_count,
|
|
qs.total_worker_time AS Total_CPU,
|
|
total_CPU_inSeconds = --Converted from microseconds
|
|
qs.total_worker_time / 1000000,
|
|
average_CPU_inSeconds = --Converted from microseconds
|
|
( qs.total_worker_time / 1000000 ) / qs.execution_count,
|
|
qs.total_elapsed_time,
|
|
total_elapsed_time_inSeconds = --Converted from microseconds
|
|
qs.total_elapsed_time / 1000000,
|
|
qp.query_plan
|
|
FROM sys.dm_exec_query_stats AS qs
|
|
CROSS apply sys.Dm_exec_sql_text(qs.sql_handle) AS st
|
|
CROSS apply sys.Dm_exec_query_plan (qs.plan_handle) AS qp
|
|
ORDER BY qs.total_worker_time DESC
|
|
OPTION (recompile);
|
|
|
|
|
|
-------------------------------------------------------------
|
|
/*** 5.TOP costliest Queries with batch and more details ***/
|
|
-------------------------------------------------------------
|
|
|
|
SELECT TOP 50
|
|
[Avg. MultiCore/CPU time(sec)] = qs.total_worker_time / 1000000 / qs.execution_count,
|
|
[Total MultiCore/CPU time(sec)] = qs.total_worker_time / 1000000,
|
|
[Avg. Elapsed Time(sec)] = qs.total_elapsed_time / 1000000 / qs.execution_count,
|
|
[Total Elapsed Time(sec)] = qs.total_elapsed_time / 1000000,
|
|
qs.execution_count,
|
|
[Avg. I/O] = (total_logical_reads + total_logical_writes) / qs.execution_count,
|
|
[Total I/O] = total_logical_reads + total_logical_writes,
|
|
Query = SUBSTRING(qt.[text], (qs.statement_start_offset / 2) + 1,
|
|
(
|
|
(
|
|
CASE qs.statement_end_offset
|
|
WHEN -1 THEN DATALENGTH(qt.[text])
|
|
ELSE qs.statement_end_offset
|
|
END - qs.statement_start_offset
|
|
) / 2
|
|
) + 1
|
|
),
|
|
Batch = qt.[text],
|
|
[DB] = DB_NAME(qt.[dbid]),
|
|
qs.last_execution_time,
|
|
qp.query_plan
|
|
FROM sys.dm_exec_query_stats AS qs
|
|
CROSS APPLY sys.dm_exec_sql_text(qs.[sql_handle]) AS qt
|
|
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
|
|
|
|
ORDER BY [Total MultiCore/CPU time(sec)] DESC; |