SQL Script To Monitor CPU Utilization
SQL Script To Monitor CPU Utilization
This post helps you in understanding and using SQL Script to Monitor CPU utilization. There are certain
scenarios where we can quickly use this script to get SQL Server CPU utilization.
When there is a performance issue, and you need to quickly check the CPU usage
Below is the SQL Script to Monitor CPU utilization. This script captures the CPU usage history report
from last 10 min. This can be customized by changing the variable “@lastNmin” value.
Transact-SQL
1 /***** Script: SQL Server CPU Utilization report from last N minutes *****/
4 /***** Output:
9 *****/
1
0
DECLARE @ts BIGINT;
1
DECLARE @lastNmin TINYINT;
1
SET @lastNmin = 10;
1 SELECT @ts =(SELECT cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info);
2
SELECT TOP(@lastNmin)
1
SQLProcessUtilization AS [SQLServer_CPU_Utilization],
3
SystemIdle AS [System_Idle_Process],
1
4 100 - SystemIdle - SQLProcessUtilization AS [Other_Process_CPU_Utilization],
1 DATEADD(ms,-1 *(@ts - [timestamp]),GETDATE())AS [Event_Time]
5
FROM (SELECT record.value('(./Record/@id)[1]','int')AS record_id,
1
6 record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]','int')A
S [SystemIdle],
1
7 record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]'
,'int')AS [SQLProcessUtilization],
1
8 [timestamp]
2
2
2
3
2
4
2
5
2
6
2
7
Transact-SQL
4 /***** Output:
8 CPUPercent: Let’s say this instance is using 50% CPU and one of the database
is using 80%. It means the actual CPU usage from the database is calculated as: (80
9
/ 100) * 50 = 40 %
10
*****/
11
WITH DB_CPU AS
12
(SELECT DatabaseID,
13
DB_Name(DatabaseID)AS [DatabaseName],
14
SUM(total_worker_time)AS [CPU_Time(Ms)]
15
FROM sys.dm_exec_query_stats AS qs
16
CROSS APPLY(SELECT CONVERT(int, value)AS [DatabaseID]
17
FROM sys.dm_exec_plan_attributes(qs.plan_handle)
18
WHERE attribute =N'dbid')AS epa GROUP BY DatabaseID)
19
SELECT ROW_NUMBER()OVER(ORDER BY [CPU_Time(Ms)] DESC)AS [SNO],
20
21 DatabaseName AS [DBName], [CPU_Time(Ms)],
From the above scripts you confirmed that there is a huge CPU utilization from one of the SQL Instance
and you identified the database which is causing high CPU. Now the next step is to identify top 10
queries which are causing high CPU utilization. Here is the SQL Script to Monitor CPU Utilization query
level. This is a wonderful script provided by SQLBlog and SQLKnowlwdge.
Note: Remember that it returns the list of costly queries which causes high CPU utilization when only
the CPU usage is >=80% from last 10 Min, otherwise it returns nothing. You can modify the script as per
your needs.
Transact-SQL
1 /***** Script: Top 10 queries that causes high CPU Utilization *****/
5 /***** Note: This script returns list of costly queries when CPU utilization is >=80%
from last 10 min ****/
6
7
SET NOCOUNT ON
8
DECLARE @ts_now bigint
9
1 DECLARE @AvgCPUUtilization DECIMAL(10,2)
0
1
SELECT @ts_now = cpu_ticks/(cpu_ticks/ms_ticks) FROM sys.dm_os_sys_info
1
1
2 -- load the CPU utilization in the past 10 minutes into the temp table, you can load
them into a permanent table
1
3 SELECT TOP(10) SQLProcessUtilization AS [SQLServerProcessCPUUtilization]
1 ,SystemIdle AS [SystemIdleProcess]
4
,100 - SystemIdle - SQLProcessUtilization AS [OtherProcessCPU Utilization]
1
5 ,DATEADD(ms, -1 * (@ts_now - [timestamp]), GETDATE()) AS [EventTime]
1 INTO #CPUUtilization
6 FROM (
1 SELECT record.value('(./Record/@id)[1]', 'int') AS record_id,
7
record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]',
1 'int')
8
AS [SystemIdle],
1
9 record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilizati
on)[1]',
2
0 'int')
2 AS [SQLProcessUtilization], [timestamp]
1 FROM (
2 SELECT [timestamp], CONVERT(xml, record) AS [record]
2
FROM sys.dm_os_ring_buffers
2
3 WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
2
6
2 -- check if the average CPU utilization was over 80% in the past 10 minutes
7
SELECT @AvgCPUUtilization = AVG([SQLServerProcessCPUUtilization] +
2 [OtherProcessCPU Utilization])
8
FROM #CPUUtilization
2
WHERE EventTime > DATEADD(MM, -10, GETDATE())
9
3
0 IF @AvgCPUUtilization >= 80
3 BEGIN
1
SELECT TOP(10)
3
2 CONVERT(VARCHAR(25),@AvgCPUUtilization) +'%' AS [AvgCPUUtilization]
3 , s.host_name
6 , DB_NAME(r.database_id) AS DatabaseName
3 , SUBSTRING (t.text,(r.statement_start_offset/2) + 1,
7
((CASE WHEN r.statement_end_offset = -1
3
8 THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
3 ELSE r.statement_end_offset
9
END - r.statement_start_offset)/2) + 1) AS [IndividualQuery]
4
, SUBSTRING(text, 1, 200) AS [ParentQuery]
0
, r.status
4
1 , r.start_time
4 , r.wait_type
2
, s.program_name
4
INTO #PossibleCPUUtilizationQueries
3
4 FROM sys.dm_exec_sessions s
4
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
4
INNER JOIN sys.dm_exec_requests r ON c.connection_id = r.connection_id
5
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
4
6 WHERE s.session_id > 50
4 AND r.session_id != @@spid
7
order by r.cpu_time desc
4
8 -- query the temp table, you can also send an email report to yourself or your
development team
4
9 SELECT *
5 FROM #PossibleCPUUtilizationQueries
0 END
5
1
-- drop the temp tables
5
2 IF OBJECT_ID('TEMPDB..#CPUUtilization') IS NOT NULL
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7
3
7
4
7
5
7
6
7
7
7
8
7
9
8
0
This script sourced from here. It results a list of stored procedures which are utilizing high CPU. This
script goes through the buffer cache and find out these results based on Total and Average worker
thread times. Below is the SQL Script to Monitor CPU Utilization from the stored procedure point of
view.
Transact-SQL
4 /***** Output:
13 *****/
14 SELECT TOP (20)
16 qs.total_worker_time AS [TotalWorkerTime],
17 qs.total_worker_time/qs.execution_count AS [AvgWorkerTime],
18 qs.execution_count,
This script sourced from here. It results a list of queries which are utilizing high CPU. Below is the SQL
Script to Monitor CPU Utilization from Ad-hoc queries.
Transact-SQL
6 st.text AS Query,
7 qs.execution_count,
8 qs.total_worker_time AS Total_CPU,
10 qs.total_worker_time/1000000,
12 (qs.total_worker_time/1000000) / qs.execution_count,
13 qs.total_elapsed_time,
15 qs.total_elapsed_time/1000000,
16 qp.query_plan
17 FROM sys.dm_exec_query_stats AS qs
Summary:
I believe these scripts will be helpful to quickly get the Instance, Database and Query level CPU
utilization reports.