mediumOther

RESOURCE_QUEUE Wait Type Explained

RESOURCE_QUEUE is a benign background wait type in SQL Server. Learn why it should be filtered from wait statistics analysis and when it can safely be ignored.

Quick Answer

RESOURCE_QUEUE is a benign background wait type used by SQL Server's internal resource monitor and related housekeeping threads as they idle on work queues. It is not an indicator of user-visible resource contention and should be filtered out of wait statistics analysis. It appears in virtually every published "waits to ignore" list, including the filter in Paul Randal's widely-used wait stats script.

Root Cause Analysis

RESOURCE_QUEUE accumulates time whenever an internal resource monitor-style thread is parked waiting for its next housekeeping task — this is expected behavior, not a sign of workload pressure. Because these background threads spend most of their lives idle, the wait time for RESOURCE_QUEUE can be very large on any healthy instance, but it does not correspond to any user query being blocked.

It is important not to conflate RESOURCE_QUEUE with RESOURCE_SEMAPHORE. RESOURCE_SEMAPHORE is the wait type that actually indicates query memory grant contention; RESOURCE_QUEUE is unrelated and is simply a background idle wait. If you see RESOURCE_QUEUE dominating wait stats, the correct action is to add it to your ignore list rather than to tune memory, MAXDOP, or Resource Governor.

Because this wait type is benign, most of the diagnostic work here focuses on confirming that RESOURCE_QUEUE is in fact being filtered from your wait-stats queries and that the actionable waits underneath it are properly surfaced.

AutoDBA checks Benign wait filtering, actionable wait type identification, and automated performance bottleneck detection across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.

Diagnostic Queries

-- Check current resource queue wait statistics
SELECT 
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    max_wait_time_ms,
    signal_wait_time_ms,
    wait_time_ms - signal_wait_time_ms AS resource_wait_time_ms
FROM sys.dm_os_wait_stats 
WHERE wait_type = 'RESOURCE_QUEUE'
AND waiting_tasks_count > 0;
-- Identify memory clerks with high allocation activity
SELECT 
    mc.type,
    mc.name,
    mc.memory_node_id,
    mc.pages_kb,
    mc.virtual_memory_reserved_kb,
    mc.virtual_memory_committed_kb,
    mc.shared_memory_reserved_kb
FROM sys.dm_os_memory_clerks mc
WHERE mc.pages_kb > 1024
ORDER BY mc.pages_kb DESC;
-- Check resource semaphore pressure and query memory grants
SELECT 
    rs.resource_semaphore_id,
    rs.target_memory_kb,
    rs.max_target_memory_kb,
    rs.total_memory_kb,
    rs.available_memory_kb,
    rs.granted_memory_kb,
    rs.used_memory_kb,
    rs.grantee_count,
    rs.waiter_count,
    rs.timeout_error_count
FROM sys.dm_exec_resource_semaphores rs;
-- Examine active memory grants and their wait states
SELECT 
    mg.session_id,
    mg.request_id,
    mg.scheduler_id,
    mg.dop,
    mg.request_time,
    mg.grant_time,
    mg.requested_memory_kb,
    mg.granted_memory_kb,
    mg.required_memory_kb,
    mg.used_memory_kb,
    mg.max_used_memory_kb,
    r.wait_type,
    r.wait_time
FROM sys.dm_exec_query_memory_grants mg
LEFT JOIN sys.dm_exec_requests r ON mg.session_id = r.session_id 
    AND mg.request_id = r.request_id
WHERE mg.grant_time IS NULL OR r.wait_type = 'RESOURCE_QUEUE'
ORDER BY mg.request_time;

Fix Scripts

Increase server memory allocation to reduce memory pressure

-- Calculate optimal max server memory (leave 4GB for OS, more for large systems)
DECLARE @TotalMemoryMB BIGINT;
SELECT @TotalMemoryMB = total_physical_memory_kb / 1024 
FROM sys.dm_os_sys_memory;

DECLARE @OptimalMaxMemory BIGINT = @TotalMemoryMB - 4096;

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'max server memory (MB)', @OptimalMaxMemory;
RECONFIGURE;

This reduces memory allocation contention by ensuring adequate memory availability. Test in development first and monitor post-change memory utilization patterns.

Configure Resource Governor to limit concurrent memory-intensive queries

-- Create resource pool with memory limits
CREATE RESOURCE POOL memory_intensive_pool
WITH (
    MIN_MEMORY_PERCENT = 10,
    MAX_MEMORY_PERCENT = 40,
    CAP_CPU_PERCENT = 50,
    MAX_DOP = 4
);

-- Create workload group
CREATE WORKLOAD GROUP memory_intensive_group
WITH (
    REQUEST_MAX_MEMORY_GRANT_PERCENT = 15,
    REQUEST_MAX_CPU_TIME_SEC = 300,
    REQUEST_MEMORY_GRANT_TIMEOUT_SEC = 120,
    MAX_DOP = 4
)
USING memory_intensive_pool;

-- Apply configuration
ALTER RESOURCE GOVERNOR RECONFIGURE;

Prevents resource queue buildup by limiting concurrent memory grants per workload group. Monitor query performance after implementation to ensure acceptable response times.

Reduce MAXDOP for memory-intensive operations

-- Set instance-level MAXDOP based on CPU cores (typically cores/2 or 8, whichever is smaller)
DECLARE @LogicalCPUs INT;
SELECT @LogicalCPUs = cpu_count FROM sys.dm_os_sys_info;

DECLARE @RecommendedMAXDOP INT = CASE 
    WHEN @LogicalCPUs >= 16 THEN 8
    WHEN @LogicalCPUs >= 8 THEN @LogicalCPUs / 2
    ELSE @LogicalCPUs
END;

EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'max degree of parallelism', @RecommendedMAXDOP;
RECONFIGURE;

Reduces parallel query memory grant conflicts by limiting concurrent thread spawning. Test with production workload patterns to verify performance impact remains acceptable.

Enable query memory grant feedback for SQL Server 2017+

-- Enable memory grant feedback at database level
ALTER DATABASE SCOPED CONFIGURATION SET ROW_MODE_MEMORY_GRANT_FEEDBACK = ON;
ALTER DATABASE SCOPED CONFIGURATION SET BATCH_MODE_MEMORY_GRANT_FEEDBACK = ON;

Memory grant feedback helps right-size memory grants over time and is relevant if your underlying problem is actually RESOURCE_SEMAPHORE contention (not RESOURCE_QUEUE, which is benign). Monitor plan cache growth and query compilation overhead after enabling.

AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.

Prevention

Configure max server memory to leave adequate headroom for OS and other applications, typically reserving 4-8GB depending on server size. Set cost threshold for parallelism to 50 or higher to prevent excessive parallel plan generation for small queries that cause resource contention.

Implement Resource Governor pools to segregate memory-intensive workloads from OLTP operations. Create dedicated pools with REQUEST_MAX_MEMORY_GRANT_PERCENT limits between 10-25% to prevent single queries from monopolizing memory resources.

Monitor memory clerk allocation patterns using sys.dm_os_memory_clerks and establish alerts when specific clerks exceed expected thresholds. MEMORYCLERK_SQLGENERAL and MEMORYCLERK_SQLQERESERVATIONS are memory clerks (not spinlocks); sustained growth of either often indicates problematic ad-hoc query patterns or oversized memory grants that warrant plan cache and query tuning.

Deploy query store to identify memory grant outliers and implement query hints or plan guides for problematic statements. Enable memory grant feedback features in SQL Server 2017+ to automatically adjust future executions based on actual memory consumption patterns.

Schedule index maintenance operations during low-activity periods to minimize buffer pool allocation conflicts. Large index rebuilds trigger significant memory clerk activity that compounds RESOURCE_QUEUE waits under concurrent load conditions.

Need hands-on help?

Dealing with persistent resource_queue issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.

Related Pages