What the Symptom Is Telling You
“SQL Server is at 100 percent CPU” describes one of four different problems, and the first two minutes decide which. The checks below are in the order that separates them fastest, and each one hands off to the script or the explainer that does the work, so this page is a route, not a fifth explanation of parallelism.
| What you see | What it usually is | Start at |
|---|---|---|
| CPU pegged, users report slowness, one or two sessions dominate | Runaway queries: a bad plan, a missing index, a scan that should be a seek | Steps 2 and 3 |
CPU high, many sessions runnable, waits dominated by SOS_SCHEDULER_YIELD | Genuine CPU pressure: more work than cores, or too much parallelism | Steps 1 and 5 |
| CPU high, connections hang or time out, THREADPOOL waits | Worker thread exhaustion, usually blocking underneath | Step 4 |
| CPU high with almost nothing running | Something outside SQL Server on the box, or the OS trimming SQL Server’s memory | Step 5 |
Step 1: Is It Working or Waiting?
Run Get Wait Statistics twice a minute apart and read the difference, not the totals; cumulative wait stats lie because the top of the cumulative list is whatever the instance has been doing since it last started. If SOS_SCHEDULER_YIELD leads the interval, threads are giving up the CPU because other threads want it: the box is genuinely busy, and the question becomes which queries. If CXPACKET leads, parallel queries are coordinating, which is normal on its own and a problem only when the same few queries are going parallel that should not. If lock waits lead, this is not a CPU problem at all; go to the blocking walkthrough instead.
Step 2: What Is Running Right Now?
Get Long-Running Queries shows every executing request with its CPU time against its elapsed time. A request whose CPU time is close to its elapsed time is working; one with high elapsed time and low CPU is waiting, and the wait type column says on what. Two or three sessions with large CPU time and status = running or runnable are usually the whole story, and statement_text tells you which statement inside the batch.
Step 3: Which Query, and Why Is It Expensive?
Get Top CPU Queries ranks the plan cache by total and average CPU, so a query that runs ten thousand times cheaply and one that runs once expensively both show up in the right place. If Query Store is on, Get Query Store Top Queries gives the same view with history, which is how you see that the plan changed on Tuesday. With the query in hand, the three usual reasons it is expensive, in the order they turn out to be true:
The plan stopped fitting its parameter. Parameter sniffing is SQL Server compiling once for the first value it saw and reusing that plan for every value after, and the post measures it rather than describing it. The statistics are stale. Get Statistics Health finds the tables whose data moved and whose statistics did not, which is the same symptom from the other side. The query is scanning when it could seek. Get Missing Indexes lists what the optimiser wanted and did not have, and Get Implicit Conversions finds the quiet data type mismatch that turns a seek into a scan without anyone changing the query.
Step 4: Are Connections Hanging as Well?
If the symptom is not only high CPU but new connections timing out, run Get Worker Threads and Active Sessions. A worker pool near its limit with THREADPOOL waits means requests cannot get a thread at all, and the usual cause underneath is blocking, every waiting session holding a thread while it waits. Get Blocking Summary finds the head of the chain; killing anything else does nothing.
Step 5: Only Now, the Settings
Get CPU Topology and OS Configuration reads what SQL Server can see: logical CPUs, schedulers online, NUMA layout, and the OS settings that decide whether Windows can take memory back from it. MAXDOP and cost threshold are the two settings people reach for first and should reach for last: MAXDOP 0 lets one query take every core, cost threshold 5 sends trivial queries parallel, and both defaults are wrong on a modern server, but changing them treats the symptom of Step 3, not the cause. Change them from the published table, once, after the queries are fixed, and watch a full business cycle.
Frequently Asked Questions
Should I lower MAXDOP to fix high CPU?
Task Manager says sqlservr.exe is at 100 percent. Is that the same thing?
CPU is high but nothing is running. What now?
How do I know whether it was always like this?
Related
- DBA Scripts: Performance and Troubleshooting, the hub this page sits under
- SQL Server Wait Statistics, every wait type on this site, searchable
- SOS_SCHEDULER_YIELD, the wait that means the CPU really is the problem
Leave a Reply