In this lesson, you will learn how to capture and analyze SQL Server workload activity using
SQL Server Profiler and Trace concepts. The goal is not to “collect everything.”
The goal is to collect the right evidence to answer performance questions like:
“Which query is slow?”, “What is causing timeouts?”, “What is running at 9:00 AM?”, and
“Which procedure consumes most CPU/reads?”
Important reality: In modern SQL Server troubleshooting, Query Store and Extended Events
are usually preferred for ongoing monitoring. However, Profiler/Trace knowledge is still valuable because:
(1) you will encounter older systems, (2) you may inherit existing trace scripts, and
(3) you must understand the difference between “useful capture” and “dangerous capture.”
You will learn:
120–180 minutes (lecture + demo + trace-reading lab)
A trace is a stream of recorded events. Each event represents something that happened inside SQL Server
(a batch executed, a stored procedure completed, a login occurred, a deadlock happened, etc.).
Tracing helps you answer: What happened? When? Who did it? and
How expensive was it?
Key teaching point: A query can have long duration with low CPU because it is waiting (I/O or locks).
Traces show you the “what,” but you still need DMVs/waits/blocking data for the “why.”
Profiler is a GUI that can capture events and display them live. “Trace” is the underlying mechanism to capture events.
The problem is not tracing itself—the problem is tracing too much with no filters, which can add overhead.
Beginners often capture too many events. That creates noise and increases overhead. Start with a small event set that answers:
“What query is slow and how expensive is it?”
Key teaching point: If your goal is “find slow queries,” capture completion events (Completed),
not every internal step. Completed events let you rank by duration/CPU/reads.
Capturing a trace is easy. The real DBA skill is reading the data correctly.
When you look at trace results, you want to answer three questions:
(1) What is the top workload? (2) Is it expensive because of work or waiting?
(3) What is the next action?
Users report “everything is slow at 9:00 AM.” A short trace during that window can show exactly what workload begins at 9:00:
a report, ETL job, index rebuild, or a single expensive stored procedure.
Capture Attention events and correlate with slow queries. This helps identify what users are timing out on.
Deadlocks can be intermittent and hard to reproduce. Capturing deadlock graph events gives you the evidence needed
to fix transaction ordering or indexing issues.
After a release, you can capture a small sample and confirm whether new queries are heavier than expected
(CPU/reads increased, new expensive procedures introduced).
Below is a training-only server-side trace template that demonstrates the right mindset:
capture only completion events, filter aggressively, and write to a file. In real production environments, many teams
prefer Extended Events—but you must understand this trace pattern because it exists in many organizations.
Safety note: Do not run tracing on production without approval and a monitoring window.
Always keep the trace short and targeted.
/* ============================================================
Training Trace Template (Server-side trace)
- Captures RPC:Completed and SQL:BatchCompleted
- Uses a duration filter (milliseconds)
- Writes to a trace file
- For LAB / TRAINING usage
============================================================ */
-- You will need appropriate permissions to run server-side traces.
-- Replace the file path with a valid path on your server.
DECLARE @TraceId INT;
DECLARE @File NVARCHAR(260) = N'C:\Temp\SQLPT_SlowQueries'; -- no extension; SQL adds .trc
DECLARE @MaxFileSize BIGINT = 50; -- MB
DECLARE @StopTime DATETIME = DATEADD(MINUTE, 5, GETDATE()); -- short capture window
-- Create trace
EXEC sp_trace_create
@traceid = @TraceId OUTPUT,
@options = 2, -- 2 = trace file rollover
@tracefile = @File,
@maxfilesize = @MaxFileSize,
@stoptime = @StopTime;
-- Events:
-- 10 = RPC:Completed
-- 12 = SQL:BatchCompleted
-- Columns (selected):
-- 1=TextData, 11=LoginName, 8=HostName, 10=ApplicationName, 35=DatabaseName
-- 13=Duration, 15=EndTime, 14=StartTime, 16=Reads, 17=Writes, 18=CPU, 48=RowCounts
-- RPC:Completed (10)
EXEC sp_trace_setevent @TraceId, 10, 1, 1;
EXEC sp_trace_setevent @TraceId, 10, 11, 1;
EXEC sp_trace_setevent @TraceId, 10, 8, 1;
EXEC sp_trace_setevent @TraceId, 10, 10, 1;
EXEC sp_trace_setevent @TraceId, 10, 35, 1;
EXEC sp_trace_setevent @TraceId, 10, 13, 1;
EXEC sp_trace_setevent @TraceId, 10, 14, 1;
EXEC sp_trace_setevent @TraceId, 10, 15, 1;
EXEC sp_trace_setevent @TraceId, 10, 16, 1;
EXEC sp_trace_setevent @TraceId, 10, 17, 1;
EXEC sp_trace_setevent @TraceId, 10, 18, 1;
EXEC sp_trace_setevent @TraceId, 10, 48, 1;
-- SQL:BatchCompleted (12)
EXEC sp_trace_setevent @TraceId, 12, 1, 1;
EXEC sp_trace_setevent @TraceId, 12, 11, 1;
EXEC sp_trace_setevent @TraceId, 12, 8, 1;
EXEC sp_trace_setevent @TraceId, 12, 10, 1;
EXEC sp_trace_setevent @TraceId, 12, 35, 1;
EXEC sp_trace_setevent @TraceId, 12, 13, 1;
EXEC sp_trace_setevent @TraceId, 12, 14, 1;
EXEC sp_trace_setevent @TraceId, 12, 15, 1;
EXEC sp_trace_setevent @TraceId, 12, 16, 1;
EXEC sp_trace_setevent @TraceId, 12, 17, 1;
EXEC sp_trace_setevent @TraceId, 12, 18, 1;
EXEC sp_trace_setevent @TraceId, 12, 48, 1;
-- Filter: only capture events longer than 500ms
-- NOTE: Trace Duration is in microseconds, so 500ms = 500,000 microseconds
DECLARE @DurationMicroseconds BIGINT = 500000;
EXEC sp_trace_setfilter @TraceId, 13, 0, 4, @DurationMicroseconds;
-- Start trace
EXEC sp_trace_setstatus @TraceId, 1;
-- To stop early (optional):
-- EXEC sp_trace_setstatus @TraceId, 0; -- stop
-- EXEC sp_trace_setstatus @TraceId, 2; -- close and delete definition
What this teaches: Filter by duration, capture only completion events, keep the window short, and write to file.
This is how you reduce overhead and still get valuable evidence.
Your trace results should end with a simple report. For example:
Top 10 by Duration, Top 10 by Reads, and Top 10 by CPU.
Then you decide next actions (execution plan review, indexing, stats, blocking checks).
Students will capture a short workload sample (lab environment) and produce a trace analysis summary with tuning next steps.
Prompt:
“You captured a trace and found one query with Duration = 20 seconds, CPU = 200 ms, Reads = 500.
What does that pattern suggest? What would you check next to confirm the real cause?”
In the next lesson, we will cover Statistics and Cardinality Estimation in SQL Server.
You will learn why the optimizer chooses certain execution plans, how wrong estimates lead to bad plans,
and how statistics influence indexing, memory grants, and overall performance stability.
Not a member yet? Register now
Are you a member? Login now