Reading a plan
Once a plan is loaded, the QPI workspace is built around one idea: get you from “here is a plan” to “here is what is wrong with it” without making you hunt. This page is a tour of the parts.
The plan bar
Along the top of the workspace is the plan bar. It carries the file name, a button to load a different plan, and a row of badges that tell you at a glance what you are looking at.
Screenshot: the plan bar across the top of the workspace, showing the file name, the Load another plan button, and the badges (Actual/Estimated, CE version, operator count, cost, captured time).
The badges include:
- Actual or Estimated: whether this plan carries real runtime numbers or only the optimizer’s estimates. Several tabs and rules only light up for actual plans, because the data simply is not in an estimated plan.
- CE version: the cardinality estimator model version the plan was compiled under. A down-level CE on a modern server is itself worth knowing about.
- Operator count and cost: the size and the optimizer’s estimated subtree cost of the plan.
- Memory desired: the memory grant the plan asked for, when present.
- Captured: when the plan was produced.
Multi-statement plans
A plan file can hold more than one statement. When it does, QPI shows a statement selector so you can step through them one at a time. Each statement gets its own findings and its own tabs. The plan bar tells you which statement of how many you are on.
Screenshot: the statement selector showing several numbered statement buttons, with one selected, above the tab bar.
The tabs
The analysis is split across tabs so each view stays focused.
| Tab | What it gives you |
|---|---|
| Overview | The query text, a plain-language summary of what the query does, execution history (when connected), and the all-important Findings list. |
| Statistics | Every statistics object the plan used, when it was last updated, how many modifications have piled up since, and how stale it is. |
| Waits | The wait breakdown for the statement, with human elapsed versus computer elapsed time, and a description for each wait type. |
| Runtime | Per-operator runtime: estimated versus actual rows, executions, logical and physical reads, plus memory-grant efficiency. |
| Indexes | The indexes on each table the plan touches, which ones the plan actually used, and missing-index suggestions you can script with one click. |
| Plan Visualization | The visual plan diagram. See The plan diagram. |
| Query Store | Coming soon. |
| Resource Governor | Coming soon. |
| Config | Settings, including how live data is loaded. |
Overview
This is home base. The query text is reformatted for readability (QPI flags that a reformatted query can hash differently and is not guaranteed to produce the same plan, so do not paste it back expecting an identical cache entry). The summary describes in words what the statement is doing. Below that sit the findings, which are covered in Understanding findings.
Statistics
For actual plans, this lists the statistics the optimizer leaned on. The columns that earn their keep are Modifications (how much the data has changed since the stats were sampled) and Age. When you are connected to the server, extra columns appear: the live row count, a staleness verdict, and an estimate-error percentage that compares what the stats believe against the table as it is right now. You can expand any row to see its histogram.
Screenshot: the Statistics tab showing the statistics table, a “Stale” badge and estimate-error percentage in the staleness column, and one row expanded to reveal its histogram chart.
Waits
Wait statistics tell you what the query was waiting on, not just how long it ran. QPI separates human elapsed (the wall-clock time you actually waited) from computer elapsed (the summed work across every worker thread), which is the honest way to talk about a parallel plan. Hover any wait type to read a description of what it means.
Screenshot: the Waits tab showing the summary row (total wait time, human elapsed, computer elapsed, waits % of CPU) above the per-wait-type table, with a wait description shown at the bottom.
Runtime
The runtime tab puts estimate against reality, operator by operator. The columns to watch are Est rows versus Actual rows (a large gap is the fingerprint of a bad estimate) and the read counts. When connected, the index seek, scan, and update counts from the live server appear alongside.
Indexes
For each table the plan touches, the Indexes tab lists the indexes on it and marks the ones the plan used. Below that, any missing-index suggestions the optimizer recorded, each with a Script button that copies a ready-to-run CREATE INDEX statement to your clipboard. Review before you run it; the optimizer’s suggestions are a starting point, not gospel.
Screenshot: the Indexes tab with the per-table sub-tabs at the top, the index list (used indexes marked), and a missing-index suggestion row with the Script button.
Where to go next
- The plan diagram for the visual layout.
- Connecting to a live server to fill in the live columns described above.
- Understanding findings for what the rules are actually looking for.