LyraLearn AI Learning Platform
Exams
← Module 1 Β· Measure First: Finding What's Actually Slow

Where the Time Actually Goes

Someone says "the report is slow." That sentence contains no information you can act on. Before you touch an index, a query, or a line of C#, you need to know which of four things is consuming the time.

The four places time hides

  1. The SQL itself β€” the server is genuinely burning CPU or reading pages. This is the part most people assume, and it is right maybe half the time.
  2. Waiting β€” the query is blocked behind someone else's lock, waiting on disk, or waiting for a memory grant. The server is doing nothing on your behalf; it is queued.
  3. Result-set transfer β€” the query finished quickly but returned 400,000 rows, and the time is spent pushing those rows over TDS to the application.
  4. Client-side rendering β€” SQL Server handed the data over promptly and the report engine is spending the time grouping, sorting, aggregating, and laying out pages in .NET.

A report that takes 90 seconds might be 4 seconds of query and 86 seconds of rendering. If you spend a week designing indexes for that report, you will have made no measurable difference and you will have no idea why.

Splitting the four before you change anything

The cheapest experiment: run the report's query directly in SSMS with the same parameter values the application uses. Three outcomes tell you three different stories.

To split "server did the work" from "sending rows took a while," use the statistics switches:

SET STATISTICS TIME ON;
SET STATISTICS IO ON;

-- paste the report's query here, with the real parameter values
SELECT TOP (1000) * FROM sys.objects;   -- placeholder: replace with your report query

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

The Messages tab now shows CPU time, elapsed time, and logical reads per table.

One caution on this measurement: SSMS itself has to render the grid. On a large result set that rendering shows up inside the elapsed time. Discard the rows to measure the server alone:

SET STATISTICS TIME ON;

-- Discard Results After Execution (Query Options > Results) also works,
-- but this pattern is explicit and survives copy-paste.
SELECT COUNT_BIG(*) FROM (
    SELECT TOP (1000) name FROM sys.objects   -- placeholder: your report query
) AS q;

SET STATISTICS TIME OFF;

If wrapping the query in COUNT_BIG makes it fast, the server was never the bottleneck β€” moving the rows was.

Ask what "slow" means before you accept the ticket

Three questions worth asking out loud, because the answers narrow the search enormously:

The short version

Decide first whether the time is in the query, in waiting, in the transfer, or in the client. SET STATISTICS TIME splits CPU from elapsed, which separates working from waiting, and running the same query without materializing rows separates server time from transfer time. Change nothing until you know which of the four you are fixing.

🧠 Quiz yourself on this lesson →

Ask the AI Tutor

Grounded in the course lessons β€” it cites its sources and says when it doesn't know.