SQL Planner User Guide — for DBAs & IT Administrators
About Wait Analysis Dashboard
SQL Planner shows you what your SQL Servers are spending their time waiting on — and which queries are responsible — so you can find and fix performance problems quickly.
Every time SQL Server runs a query, parts of that work involve waiting: waiting for a disk read, waiting for a lock to be released, waiting for memory, waiting to write to the transaction log. SQL Planner samples these waits continuously, adds them up, and attributes them to the exact SQL statement that caused them.
The practical result: instead of guessing from "CPU looks high," you can answer the real question directly — "which statements are slow, and what are they waiting for?" That is the fastest route to a fix, because the wait type usually points straight at the cause (a missing index, blocking, slow storage, and so on).
The pages at a glance
Wait-Time Analysis
The main dashboard. See waits over time, by category, drill into any time period, and find the top waiting queries.
Query Detail
Deep dive on a single statement: full text, tuning findings, suggested indexes, execution stats, and the execution plan.
Wait Alerts
Automatic alerts when a server's waits are unusually high compared to its own normal weekly pattern.
Collector Health
Confirms data is actually being collected, so you can trust that "no alerts" really means "all healthy."
Wait-Time Analysis (the main dashboard)
This is where you spend most of your time. The left panel has two controls; the right side shows a chart and a table.
1. Choose a server
The Server dropdown selects which SQL Server you're looking at. There is also a special All Servers (overview) option at the top.
- A specific server — the chart breaks waits down by category (Disk I/O, Locking, etc.) for that one server.
- All Servers (overview) — the chart breaks waits down by server, so each colored segment is a whole server. Use this to spot, across your whole estate, which server is the busiest. Click that server's segment to jump straight into its detailed view.
2. Choose a timeframe
The Timeframe dropdown ranges from Last 1 Hour up to Last 90 Days. SQL Planner automatically picks the right level of detail: recent timeframes show fine-grained data (down to 5-minute bars), while longer ones show daily bars for a clean trend.
Reading the chart
The chart is a stacked bar chart. Each bar is a slice of time (an hour, a day, etc.). The total height is the total wait time in that slice; the colored segments show how that total splits up.
Colors
In single-server view, each color is a wait category, and colors are fixed — Disk I/O is always the same blue, Locking is always red — so you learn to read the chart at a glance:
Disk I/O Transaction Log Locking / Blocking Memory CPU Buffer Latch Network / Client External / OS
Units
The vertical axis label tells you the unit — Wait Time (s), (min), or (hr). SQL Planner picks the most readable unit automatically based on how large the values are, so you never see an unreadable number like "2,460,000 ms."
Filtering categories (single-server view)
Click any category name in the legend below the chart to hide it. The bars, the grid, and the percentages all update to exclude it. This is useful when one huge category (often Disk I/O) hides everything else — hide it, and the smaller waits become readable. Click the name again to bring it back.
Drilling down
The chart is interactive. Click a bar to zoom into that time period at a finer resolution:
The breadcrumb above the chart always shows the exact window you're viewing, in UTC. As you drill, the statements grid below updates to match — so you're always seeing the queries that were waiting in that specific window.
The "Top 50 Waiting SQL Statements" grid
Below the chart is the list of statements that waited the most in the current view, highest first. Columns:
| Column | What it tells you |
|---|---|
| Server | (Overview only) which server the statement ran on. |
| SQL Statement | The statement text (click it to open Query Detail). The grey line beneath is its fingerprint. |
| Category | The kind of wait this row represents (Disk I/O, Locking, etc.). |
| Wait Type | The exact underlying wait (e.g. PAGEIOLATCH_SH). |
| Total Wait Time | How much time was spent waiting, auto-scaled (ms / s / min / hr). |
| Percentage | This row's share of the total wait in the current view. |
| Executions | How many times the statement ran in the window. |
| Findings | Tuning hints detected from the execution plan (see badges below). |
Finding badges
If SQL Planner spots a tuning opportunity in the statement's plan, it shows a badge:
Missing index a useful index doesn't exist Scan reading a whole table/index Implicit conversion a datatype mismatch slowing things Key lookup extra lookups that an index could cover tempdb spill ran out of memory, spilled to disk
Query Detail
Clicking a statement opens its detail page, which gives you everything needed to act:
- Full statement text — the complete SQL, not the truncated grid version.
- Findings — the same badges, expanded with specifics (e.g. the missing index's estimated impact).
- Suggested index — ready-to-review
CREATE INDEXDDL when a missing index was detected. - Execution statistics — execution count, CPU, reads, and related metrics.
- Execution plan — download the
.sqlplanfile to open in SQL Server Management Studio.
Wait Alerts
SQL Planner learns each server's normal weekly pattern — what its waits typically look like at, say, 9am on a Tuesday versus 3am on a Sunday — and raises an alert when an hour is unusually high compared to that normal. This is far more useful than a fixed threshold, because "normal" is different for a busy weekday morning than a quiet weekend night.
Reading an alert
| Column | Meaning |
|---|---|
| Severity | Critical = far outside normal; Warning = notably outside normal. |
| Server / Category | Which server and which kind of wait spiked. |
| When (UTC) | The hour that triggered, plus its day/time-of-week. |
| Observed vs Normal | What actually happened vs. the learned baseline for that hour. |
| Deviation | How far outside normal — e.g. 4.3σ means "4.3 standard deviations above normal." |
| Status | Open, Acknowledged, or Resolved. |
The triage workflow
Collector Health
This page answers a critical question: is data actually being collected? Without it, an empty alert list is ambiguous — it could mean "everything's healthy" or "the collector died and we're blind." This page removes that doubt.
Per-server status
Each server shows a status based on how recently it sent data:
| Status | Meaning | Action |
|---|---|---|
| Healthy | Fresh data arriving (within the last few minutes). | None. |
| Stale | No data for several minutes — collector may be lagging, or the server is idle. | Check the collector task; verify whether the server is genuinely idle. |
| Down | No data for over 10 minutes, or never. | The collector for that server likely stopped — investigate. |
Other columns: Coverage (of the last 60 minutes, how many actually have data — a gap detector), Query insight freshness, Lease (whether it's collecting right now), and Last error.
Background jobs
The lower panel shows the freshness of the scheduled maintenance jobs — Hourly rollup, Baseline build, and Alert evaluator. If any of these reads "days ago" or "never," its scheduled task isn't running, and the features that depend on it (long-range charts, alerts) will be stale. This is the page that tells you to go check your scheduled tasks.
Common tasks (quick playbook)
"A server feels slow right now"
- Open Wait-Time Analysis, pick the server, set timeframe to Last 1 Hour.
- Look at the tallest recent bar and its dominant color — that's the bottleneck category.
- Click that bar to drill into 5-minute detail; check the grid for the top waiting statement.
- Click the statement → review findings and suggested index on Query Detail.
"I received a Critical alert"
- Open Wait Alerts, find the alert, click Acknowledge.
- Note its server, category, and hour. Go to Wait-Time Analysis, pick that server.
- Set the timeframe to cover that hour and drill in; identify the driving query.
- Fix or rule out, then return and Resolve the alert.
"The dashboard shows no data"
- Open Collector Health. Is the server Down? The collector isn't sending data.
- Check the Background jobs panel — is the hourly rollup current? If not, long-range views will be empty.
- Confirm the scheduled tasks (collector, and the maintenance job) are running.
"Which server in my estate is worst?"
- Open Wait-Time Analysis, choose All Servers (overview), set a wide timeframe.
- The tallest bars and largest colored segments are your busiest servers.
- Click a server's segment to jump into its detailed view.
Wait categories — what they usually mean
| Category | Typically points to… |
|---|---|
| Disk I/O | Slow storage, missing indexes causing large reads, or memory pressure forcing disk reads. |
| Transaction Log | Heavy writes, slow log storage, or frequent small transactions. |
| Locking / Blocking | One query blocking others — contention, long transactions, or lock escalation. |
| Memory | Memory grants waiting — large sorts/hashes, or overall memory pressure. |
| CPU | CPU pressure or thread starvation — too much work for available cores. |
| Buffer Latch | In-memory page contention — often hot pages or tempdb contention. |
| Network / Client | The application/client is slow to consume results — usually app-side, often benign. |
| External / OS | Time spent outside SQL Server (OS calls, extended procedures). |
Glossary
| Term | Plain meaning |
|---|---|
| Wait | Time SQL Server spends not running a query because it's waiting for something (disk, lock, memory…). |
| Wait type | The specific thing being waited on (e.g. PAGEIOLATCH_SH = waiting for a data page to be read from disk). |
| Category | A friendly grouping of related wait types (Disk I/O, Locking/Blocking, etc.). |
| Baseline / "normal" | What a server's waits typically look like at a given hour of the week, learned from recent history. |
| Sigma (σ) | How far outside normal something is. 3σ ≈ unusual; 6σ ≈ very unusual. |
| Drill-down | Clicking a bar to zoom into a smaller, more detailed time window. |
| Coverage | Of the last hour, how many minutes actually have collected data (a gap check). |
| UTC | All times in SQL Planner are shown in UTC for consistency across servers. |
FAQ
Why are all times in UTC?
So that data from servers in different time zones lines up consistently, and there's no daylight-saving ambiguity. Times are labelled "(UTC)" throughout.
Why does an idle server sometimes show as "Stale"?
If a server genuinely had no waits in a minute, no data is written for that minute, so the freshness check can briefly read as stale even though the collector is fine. Coverage and the background-jobs panel help you tell a quiet server from a stopped collector.
Why is my Wait Alerts page empty?
Either everything is within normal range (good), or the system is still learning. The baseline needs a few weeks of history before it raises alerts confidently — until then it stays deliberately quiet to avoid false alarms.
An alert fired but the number looks small — why?
Alerts are about deviation from normal, not absolute size. An hour that's small in absolute terms can still be flagged if it's far above what's normal for that server at that time — though a minimum floor prevents trivially tiny spikes from alerting.
The chart shows grouped bars instead of one stacked bar — is that wrong?
The chart is designed to be stacked (one bar per time slice). If you ever see separate side-by-side bars, refresh the page; it's a display glitch, not a data problem.