CPU Pressure or Time to Tune a Query?

CPU Pressure Feature Image SQLMCT

Recently while discussing the Task Execution Model and Thread Scheduling, I was asked the following question, When discussing worker threads, how can we determine whether we should increase CPU capacity or focus on query tuning? This is when our worker threads are under pressure and the instance is becoming exhausted?

In my brain, I thought, that is a great question, and it’s exactly the right way to think about worker thread pressure vs. real CPU starvation, especially when worker threads are getting tight. Let’s write a post.

Worker Threads vs CPU Utilization

When managing SQL Server performance, it’s important to understand the relationship, and the difference, between worker threads and CPU utilization. They’re separate objects, and they don’t always move together. You can be running hot on CPU and still have worker threads available, or you can run out of worker threads even when CPU usage looks fine.

Think of it like a busy restaurant.

Worker threads are your waitstaff and kitchen crew, the people who can actually do the work. They take orders, cook meals, and deliver plates. If you run out of staff, customers start lining up, no matter how good your kitchen equipment is.

CPU is the energy and speed of that staff, how fast they can move, cook, and serve while they’re on the clock. Strong CPU means your cooks slice faster and your servers hustle between tables.

Now imagine the dining room is full, all tables are seated, and every server is already working a section. Orders are piling up at the host stand, but there’s no one left to take them. That’s a thread pool wait situation. The restaurant isn’t slow because the staff is exhausted, the problem is that every worker is already busy.

On the flip side, you might have plenty of servers standing around, but the kitchen equipment is struggling. One oven, already maxed out, is trying to handle every order. That’s high CPU utilization. You have workers available, but the core machinery can’t keep up, so meals still come out slow.

Here is the key point:

Adding more capacity doesn’t help if the dining room has no servers left. Putting in a bigger oven won’t seat more guests if you’re short-staffed. And hiring more servers doesn’t help if the kitchen is already overheated and maxed out.

Performance depends on having enough workers to handle demand and enough CPU to keep them moving efficiently. Simply adding CPU is like buying stadium-quality grills when what you really needed was more staff on the floor, great power, wrong fix.

Below are steps you can use in SQL Server to determine whether you should scale CPU or focus on query or workload tuning.

Separate CPU pressure from worker-thread pressure 

They often appear together, but they are not the same problem. 

Symptom What it might indicate 
High CPU % CPU-bound workload or inefficient queries 
High Number of RUNNABLE tasks CPU scheduler pressure 
High Number of THREADPOOL waits Worker thread exhaustion 
Low CPU, but THREADPOOL waits Blocking, parallelism abuse, or thread hoarding 

The key is where tasks are stuck: 

  • RUNNABLE QUEUE – Waiting for CPU 
  • SUSPENDED QUEUE – Waiting for a resource other than the CPU (lock, I/O, latch) 
  • THREADPOOL WAIT – waiting for a worker thread 

Using sys.dm_os_schedulers to determine CPU Pressure

The sys.dm_os_schedulers dynamic management view tells you whether SQL Server wants more CPU. 

SELECT scheduler_id, runnable_tasks_count, current_tasks_count, 
	active_workers_count, load_factor 
FROM sys.dm_os_schedulers 
WHERE status = 'VISIBLE ONLINE';
Observation Interpretation Action 
Runnable_tasks_count > 0 consistently across schedulers CPU pressure Tune queries or add CPU 
Runnable_tasks_count = 0
but queries still slow 
Not CPU-bound Look elsewhere 
High load_factor on many schedulers Sustained CPU contention Tune first, then scale 

Consistently non-zero runnable tasks is the clearest indicator that CPU is the bottleneck.

Correlate CPU% with Wait Types

Wait type Meaning 
SOS_SCHEDULER_YIELD CPU scheduling pressure 
THREADPOOL No worker threads available 
High signal wait time CPU starvation 
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms 
FROM sys.dm_os_wait_stats 
WHERE wait_type IN ('SOS_SCHEDULER_YIELD', 'THREADPOOL');
  • High SOS_SCHEDULER_YIELD + high runnable tasks = CPU-bound workload
  • High THREADPOOL waits + low CPU = Blocking, parallelism abuse, or thread hoarding 

Performance Monitor Counters

Confirm CPU pressure with these Operating System and SQL Server performance monitor counters:

/* Perf counters via DMV: CPU saturation + CPU queuing + SQL throughput */
SELECT pc.object_name, pc.counter_name, pc.cntr_value, pc.cntr_type, GETDATE() AS sample_time
FROM sys.dm_os_performance_counters AS pc
WHERE 
    -- OS CPU saturation
    (pc.object_name LIKE '%Processor%' 
     AND pc.counter_name = '% Processor Time')
    OR
    -- OS CPU queuing
    (pc.object_name LIKE '%System%'
     AND pc.counter_name = 'Processor Queue Length')
     OR
    -- SQL throughput
    (pc.object_name LIKE '%SQL Statistics%'
     AND pc.counter_name = 'Batch Requests/sec')
ORDER BY
    pc.object_name, pc.counter_name;

Checking Thread Pool Utilization

To determine how close you are to the thread pool ceiling, compare current worker count to the configured maximum:

-- Current worker threads in use
SELECT COUNT(*) AS current_workers FROM sys.dm_os_workers;

-- Maximum configured worker threads
SELECT max_workers_count FROM sys.dm_os_sys_info;

If the current worker count approaches max_workers_count and THREADPOOL waits are occurring, you’ve hit the thread capacity. SQL Server dynamically creates threads up to this maximum; if no idle worker thread is available when the limit is reached, the client’s command must wait.

THREADPOOL wait occurs when there are no available threads in the server’s thread pool, which can lead to login failures or queries not being able to run. Short-duration THREADPOOL waits during sudden demand spikes are normal as the thread pool grows. When there are no available threads at all, that constitutes worker thread starvation, which is not normal.

Decide: CPU upgrade or query tuning? 

Scale Up CPU

Only when CPU is persistently 80–90%+ utilized, runnable task queues are building, signal wait times are growing, and top queries are already optimized; adding cores or faster processors is likely needed.

Tune Workload

When worker threads are exhausted (THREADPOOL waits) but CPU isn’t maxed, the bottleneck is concurrency or query inefficiency. A worker is never released until its task completes, even if that task is just waiting on a lock, so blocking, parallelism abuse, or thread hoarding are the real targets.

Find Root Cause

Always diagnose why threads are stuck before choosing a remedy. Adding CPU to a system choked by a single blocking query or excessive parallelism wastes budget and masks the real problem.

References:

Share and Enjoy !

Shares

Be the first to comment on "CPU Pressure or Time to Tune a Query?"

Leave a comment

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.