DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How To Approach Java, Databases, and SQL [Video]
  • How to Restore a Transaction Log Backup in SQL Server
  • How to Attach SQL Database Without a Transaction Log File
  • A Deep Dive into Apache Doris Indexes

Trending

  • A Complete Guide to Modern AI Developer Tools
  • Optimizing Integration Workflows With Spark Structured Streaming and Cloud Services
  • Orchestrating Microservices with Dapr: A Unified Approach
  • A Simple, Convenience Package for the Azure Cosmos DB Go SDK
  1. DZone
  2. Data Engineering
  3. Databases
  4. How To Send SQL Server CPU Utilization Alerts Using SQL Server Agent

How To Send SQL Server CPU Utilization Alerts Using SQL Server Agent

This article explains how to send an email alert using SQL Server alerts when the SQL Server CPU utilization reaches a specific threshold.

By 
Nisarg Upadhyay user avatar
Nisarg Upadhyay
·
Apr. 27, 23 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
8.5K Views

Join the DZone community and get the full member experience.

Join For Free

In Microsoft SQL Server, you can use T-SQL and SQL Server Agent to generate an alert when CPU usage exceeds a threshold, such as 80%. Here's an example of how you can achieve this:

  1. Create a SQL Server Agent alert: Open SQL Server Management Studio (SSMS) and connect to your SQL Server instance. Navigate to the SQL Server Agent node in the Object Explorer, right-click on the "Alerts" folder, and select "New Alert."
  2. Configure the alert properties: In the "New Alert" dialog, configure the following properties:
    1. Name: Provide a name for the alert.
    2. Type: Select the type of alert as "SQL Server performance condition alert."
    3. Object: Choose the "Resource Pool Stats."
    4. Counter: Choose the "CPU Usage target %" counter.
    5.  Instance: Select "default" to monitor the overall CPU usage of the entire system.
    6. Alert if counter: Choose "Rises above" to trigger the alert when CPU usage exceeds the threshold.
    7. Value: Enter "0.8" to set the threshold for CPU usage to 80%.
    8.  Enable this alert: Check this option to enable the alert.
    9. Response: Choose the appropriate response action, such as "Notify operators" or "Execute job" to determine what action should be taken when the alert is triggered.
    10. Additional actions: As needed, you can configure additional actions, such as sending an email or running a script.
  3. Click on "OK" to create the alert.

Once the alert is created, SQL Server Agent will automatically monitor the CPU usage based on the specified threshold. When the CPU usage exceeds 80%, the alert will be triggered, and the configured response action will be executed, such as sending notifications or running a script.

T-SQL Stored Procedure To Send CPU-Intensive Queries

Let us understand this with a simple demonstration. Suppose I want to create an alert when the CPU utilization reaches 80%; the SQL Server automatically sends the alert along with the list of the top 10 CPU-intensive queries. We will email the queries in an HTML table.

We can use the following query to populate the top 10 CPU-intensive queries list.

MS SQL
 
SELECT TOP 10 session.session_id, 
           req.cpu_time, 
           req.logical_reads, 
           req.reads, 
           req.writes, 
           SUBSTRING(sqltext.TEXT, (req.statement_start_offset / 2) + 1, 
           ((CASE req.statement_end_offset 
                WHEN -1 THEN DATALENGTH(sqltext.TEXT) 
                ELSE req.statement_end_offset 
            END - req.statement_start_offset) / 2) + 1) AS statement_text, 
           COALESCE(QUOTENAME(DB_NAME(sqltext.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(sqltext.objectid, sqltext.dbid))  
           + N'.' + QUOTENAME(OBJECT_NAME(sqltext.objectid, sqltext.dbid)), '') AS command_text, 
  	     req.command, 
           session.login_name, 
           session.host_name, 
           session.program_name, 
           session.last_request_end_time,	
           session.login_time   	
FROM sys.dm_exec_sessions AS session 
JOIN sys.dm_exec_requests AS req ON req.session_id = session.session_id CROSS APPLY sys.Dm_exec_sql_text(req.sql_handle) AS sqltext 
WHERE req.session_id != @@SPID 
ORDER BY req.cpu_time DESC 


Query Output 

Query output

The second step is storing query output in a temporary table. The table definition and INSERT query are following:

MS SQL
 
create table #tbl_HighCPU_Query_Output
(
sessionID int,
cpu_time bigint,
logicalReads bigint,
Reads Bigint,
writes bigint, QueryStatement varchar(max), command_text varchar(max), command varchar(1500),
login_name varchar(1000),
hostname varchar(50),
program_name varchar(500),
last_request_end_time datetime,
login_time datetime
)
INSERT INTO #tbl_HighCPU_Query_Output
SELECT TOP 10 session.session_id, 
           req.cpu_time, 
           req.logical_reads, 
           req.reads, 
           req.writes, 
           SUBSTRING(sqltext.TEXT, (req.statement_start_offset / 2) + 1, 
           ((CASE req.statement_end_offset 
                WHEN -1 THEN DATALENGTH(sqltext.TEXT) 
                ELSE req.statement_end_offset 
            END - req.statement_start_offset) / 2) + 1) AS statement_text, 
           COALESCE(QUOTENAME(DB_NAME(sqltext.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(sqltext.objectid, sqltext.dbid))  
           + N'.' + QUOTENAME(OBJECT_NAME(sqltext.objectid, sqltext.dbid)), '') AS command_text, 
           req.command, 
           session.login_name, 
           session.host_name, 
           session.program_name, 
           session.last_request_end_time,	
           session.login_time   	
FROM sys.dm_exec_sessions AS session 
JOIN sys.dm_exec_requests AS req ON req.session_id = session.session_id CROSS APPLY sys.Dm_exec_sql_text(req.sql_handle) AS sqltext 
WHERE req.session_id != @@SPID 
ORDER BY req.cpu_time DESC 


The third step is to create a dynamic query with HTML tags to display the query output in tabular format. The script is below: 

MS SQL
 
DECLARE @HTMLString nvarchar(max)  
SET @HTMLString= 
' 
<H2>Top 10 CPU Intesnive Queries</H2> 
<table id="AutoNumber1" borderColor="#111111" border="1"> 
   <tr> 
  <td bgcolor="#99CC33">session ID</td> 
  <td bgColor="#99CC33">CPU Time</td> 
  <td bgcolor="#99CC33">Logical Reads<</b></td> 
  <td bgcolor="#99CC33">Reads</td> 
  <td bgcolor="#99CC33">Writes</td> 
  <td bgcolor="#99CC33">Stored Procedure</td> 
  <td bgcolor="#99CC33">Command</td> 
  <td bgcolor="#99CC33">Login name</td> 
  <td bgcolor="#99CC33">hostname</td> 
  <td bgColor="#99CC33">program_name</td> 
  <td bgcolor="#99CC33">last_request_end_time</b></td> 
  <td bgcolor="#99CC33">login_time</td> 
   </tr>' 
+CAST((SELECT distinct 
  td =  sessionID ,' ' , 
 td= cpu_time ,' ' , 
 td = logicalReads,' ' , 
 td = Reads,' ' , 
 td = writes,' ',  
 td = DBObject,' ' , 
 td = command,' ' , 
 td = login_name,' ' , 
 td =  hostname ,' ' , 
 td= program_name ,' ' , 
 td = last_request_end_time,' ' , 
 td = login_time,' '  
  
FROM  
 #tbl_HighCPU_Query_Output WHERE program_name not like '%Mail%'  
  
 FOR XML PATH('tr'), TYPE) AS NVARCHAR(MAX))+'</table>'


The fourth step is to configure database mail to send the alert. You can read this article to learn how to configure the database mail in SQL Server. The entire stored procedure is following:

MS SQL
 
USE dbatools

 go

 ALTER PROCEDURE Sp_send_highcpu_alert
 AS
   BEGIN
       CREATE TABLE #tbl_highcpu_query_output
         (
            sessionid             INT,
            cpu_time              BIGINT,
            logicalreads          BIGINT,
            reads                 BIGINT,
            writes                BIGINT,
            querystatement        VARCHAR(max),
            command_text          VARCHAR(max),
            command               VARCHAR(1500),
            login_name            VARCHAR(1000),
            hostname              VARCHAR(50),
            program_name          VARCHAR(500),
            last_request_end_time DATETIME,
            login_time            DATETIME
         )

       INSERT INTO #tbl_highcpu_query_output
       SELECT TOP 10 session.session_id,
                     req.cpu_time,
                     req.logical_reads,
                     req.reads,
                     req.writes,
                     Substring(sqltext.text, ( req.statement_start_offset / 2 ) +
                                             1
                     , (
                     (
                     CASE req.statement_end_offset
                       WHEN -1 THEN Datalength(sqltext.text)
                       ELSE req.statement_end_offset
                     END - req.statement_start_offset ) / 2 ) + 1)
                     AS statement_text,
                     COALESCE(Quotename(Db_name(sqltext.dbid)) + N'.'
                              + Quotename(Object_schema_name(sqltext.objectid,
                              sqltext.dbid))
                              + N'.'
                              + Quotename(Object_name(sqltext.objectid,
                              sqltext.dbid)),
                     '') AS
                     command_text,
                     req.command,
                     session.login_name,
                     session.host_name,
                     session.program_name,
                     session.last_request_end_time,
                     session.login_time
       FROM   sys.dm_exec_sessions AS session
              JOIN sys.dm_exec_requests AS req
                ON req.session_id = session.session_id
              CROSS apply sys.Dm_exec_sql_text(req.sql_handle) AS sqltext
       WHERE  req.session_id != @@SPID
       ORDER  BY req.cpu_time DESC

       DECLARE @HTMLString NVARCHAR(max)
       DECLARE @SUBJECT VARCHAR(max) = 'High CPU Alert on: ' + @@servername + '.'

       SET @HTMLString= '   <H2>Top 10 CPU Intesnive Queries</H2>   <table id="AutoNumber1" borderColor="#111111" border="1">      <tr>     <td bgcolor="#99CC33">session ID</td>     <td bgColor="#99CC33">CPU Time</td>     <td bgcolor="#99CC33">Logical Reads<</b></td>     <td bgcolor="#99CC33">Reads</td>     <td bgcolor="#99CC33">Writes</td>     <td bgcolor="#99CC33">Query Statement</td>     <td bgcolor="#99CC33">Stored Procedure</td>     <td bgcolor="#99CC33">Command</td>     <td bgcolor="#99CC33">Login name</td>     <td bgcolor="#99CC33">hostname</td>     <td bgColor="#99CC33">program_name</td>     <td bgcolor="#99CC33">last_request_end_time</b></td>     <td bgcolor="#99CC33">login_time</td>      </tr>'
                        + Cast((SELECT DISTINCT td = sessionid, ' ', td= cpu_time
                        ,
                        ' ',
                        td = logicalreads, ' ', td = reads, ' ', td = writes, ' '
                        ,
                        td =
                        querystatement, ' ', td = command_text, ' ', td = command
                        ,
                        ' ',
                        td = login_name, ' ', td = hostname, ' ', td=
                        program_name,
                        ' '
                        , td = last_request_end_time, ' ', td = login_time, ' '
                        FROM
                        #tbl_highcpu_query_output WHERE program_name NOT LIKE
                        '%Mail%'
                        FOR xml path('tr'), type) AS NVARCHAR(max))
                        + '</table>'

       SELECT @HTMLString

       -- Send email using sp_send_dbmail  
       EXEC msdb.dbo.Sp_send_dbmail
         @profile_name = 'YourProfile',
         -- Replace with the name of your DbMail profile  
         @recipients = 'YourRecipients',
         @subject = @subject,
         @body = @HTMLString,
         @body_format = 'HTML';
   END 


Configure Alert

Create a database alert, as I explained at the article's beginning. The alert parameters should be as shown in the screenshot below.

Alert parameters

When the alert is raised, we want to send the list of CPU-intensive queries. To do that, we must create an SQL Job. I have created a SQL Server Agent job named Populate_High_CPU_Queries. The SQL Job executes the sp_send_HIGHCPU_Alert stored procedure. You can read this article to learn how to create an SQL Server agent job.

In our case, the job step should look like the following image:

New job step

Once the SQL job named Populate_High_CPU_Queries is created, you can specify the job name in the response option of the alert. Below is the image of the Response tab for reference.

Response tab

Here I am using my demo setup, and I am not able to replicate the 80% instance CPU utilization. Hence, the SQL server will not trigger an alert. But for reference, I have manually executed the stored procedure. The procedure sent a mail with a list of queries which looks like the following image:

Mail sent with list of queries

I would like to reference a product named dbForge Studio for SQL Server. dbForge Studio for SQL Server has a feature named SQL Monitor which provides many details and real-time monitoring of the SQL Server resource utilization. This feature is helpful because you can see the status of the entire database server from one central dashboard. Now, when viewing real-time data, you might not use the alerts and keep an eye on CPU utilization %. When you see the spike in CPU, you can directly open the Top Queries tab, which shows the details of resource-intensive queries. The SQL Monitor looks like the following image.

SQL Monitor

The screenshot of the Top Queries feature: 

Top queries feature

Summary

In this article, we learned how to create an alert based on CPU utilization using SQL Server Alerts. Also, we learned how to send an HTML-formatted email using the SQL Server database mail feature.

Database HTML sql Transact-SQL

Opinions expressed by DZone contributors are their own.

Related

  • How To Approach Java, Databases, and SQL [Video]
  • How to Restore a Transaction Log Backup in SQL Server
  • How to Attach SQL Database Without a Transaction Log File
  • A Deep Dive into Apache Doris Indexes

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!