What is RESOURCE_SEMAPHORE_QUERY_COMPILE?
Before we understand the RESOURCE_SEMAPHORE_QUERY_COMPILE let us see what is compile memory.
Compile memory: When a query is compiled in SQL Server, the compilation process needs memory (for parsing, algeberaization and optimization) called compile memory. This memory doesn’t include the memory required to execute the query.
Challenges with Compile memory: This memory used for Query compilations are usually expected to fit into SQL Server main-memory and to be relatively short-lived. Like any other consumers of Bpool, this is implemented by “stealing” pages from the Buffer Pool and hence it blocks other memory consumers from using that memory until a query compilation completes.
Even if the SQL Server has enough memory to service multiple simultaneous query compilation, allowing all of them to occur at the same time might lead to stealing a significant number of pages from the buffer pool, with consequent increased physical IO , poor performance of query execution and causing memory pressure within SQL Server. However on the other side, a throttling mechanism that is too restrictive could lead to a non-optimal usage of the system resources and decreased throughput for compile intensive workloads, So SQL Server came with more dynamic approach to solve the problem which is to better manage system resources, memory in particular. Such management should hence be based on and driven by the amount of memory used.
Let us see it with example:
Assume SQL Server Max server memory is set to 1000MB and Currently data /index pages is consuming 800MB with in Max server memory (bpool) and 3 queries are reaching SQL Server for compilation, each of them requiring 300 MB for compilation.
If all three queries are compiled simultaneously total compilation might take 900MB of memory causing all the data and index pages to be dropped from BPOOL causing consequent increased physical IO and poor performance of query during execution(to bring data pages back to memory). On the other hand let us assume each of this 3 queries need only 2 MB of compilation memory, There is no reason for SQL Server to throttle the number of compilation.
To overcome above challenges SQL 2005+ throttles the number of concurrent compiles that can happen at any time based on memory usage during the compile. SQL Server memory grant is controlled by a object called “Resource Semaphore” and has internal mechanism to detect how much memory has been used by each compile. There are three gateways (semaphores) called the small, medium, and big gateway. When a request is received for compilation SQL Server will start compilation. There is no limit on how many queries can be compiled simultaneously, but when memory usage for a query reaches the threshold for a given gateway it will then acquire that semaphore of next gateway before continuing. The semaphores (Queries which can be compiled concurrently) are set up to allow 4*schedulers count for the small gateway, 1*schedulers count for the medium gateway and 1 (per SQL instance) for the big gateway.
The small gateway has a fixed threshold for how much memory must be consumed before you enter it. The medium and big gateways have dynamic thresholds that vary depending on how much memory is available, how much is stolen, etc.
If the semaphore can’t be acquired then you see this wait type (Query is waiting for memory grant to compile a query = RESOURCE_SEMAPHORE_QUERY_COMPILE wait). This behavior lets SQL Server to allow only a few memory-intensive compilations occur at the same time. Additionally, this behavior maximizes throughput for smaller queries.
How to identify RESOURCE_SEMAPHORE_QUERY_COMPILE waits?
To get an idea look at the sys.sysprocesses table for sessions waiting on RESOURCE_SEMAPHORE_QUERY_COMPILE
select sp.*, st.text from sys.sysprocesses sp CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) AS st
WHERE sp.lastwaittype LIKE ‘RESOURCE_SEMAPHORE_QUERY_COMPILE%’ ORDER BY sp.waittime DESC;
There could be two possible reasons for RESOURCE_SEMAPHORE_QUERY_COMPILE waits
1. Memory pressure within SQL Server caused by others using lot of stolen memory or OS memory pressure
In this case you will see thresholds for medium and big gateways very low. In this situation you have to identify who is consuming most of stolen memory and tune them to increase the available memory or add additional memory that can used by SQL server. When the available memory decrease, threshold for medium and big gateways would decrease significantly and increase the number of queries which have to enter medium /big gateways, So the number of parallel compiles will decrease increasing the overall wait time.
This DBCC memory status output is from system which has 48 processor and has excessive RESOURCE_SEMAPHORE_QUERY_COMPILE waits because of memory pressure.
Small Gateway (default) Value
—————————————- ———–
Configured Units 192 // 190 number of units . 48 CPU’s * 4=192
Available Units 109
Acquires 83
Waiters 0
Threshold Factor 380000
Threshold 380000
(6 row(s) affected)
Medium Gateway (default) Value
—————————————- ———–
Configured Units 48 //48 number of units. SO 48 CPU’s *1=48
Available Units 0 //There is no available slots. All slots are busy.
Acquires 48
Waiters 34 //34 Queries are waiting
Threshold Factor 12
Threshold 2204603 //Threshold is very low 2 MB (This value is in bytes)
(6 row(s) affected)
Big Gateway (default) Value
—————————————- ———–
Configured Units 1 //1 per instance
Available Units 0 //There is no available slots. All slots are busy.
Acquires 1
Waiters 47 // 47 Queries are waiting
Threshold Factor 8
Threshold 3306905 //Threshold is very low 3 MB (This value is in bytes)
2. There is huge amount of available memory but the available units in gateway is exhausted. This situation normally occurs when we have many queries that have high compile time and use lot of memory for compilation.
Compile time and Compile memory can be captures using the show plan XML for query compile event in profiler.
Below is extract from show plan XML for query compile event in profiler. This query has used approximately 150 MB of compile memory and the threshold for Big gateway is around 143 MB . So only one query which needs more than 143 MB can compile at a time , This can cause contention when there are multiple queries waiting for compile/recompile. Also an important factor to notice in this XML plan is compile time is ~139 times the CPU. So likely this query waited for most of the time for resource semaphore.
Big Gateway (default) Value
—————————————- ———–
Configured Units 1
Available Units 0
Acquires 1
Waiters 47
Threshold Factor 8
Threshold 149640500
<QueryPlan CachedPlanSize="312" CompileTime="139847" CompileCPU="1002" CompileMemory="152320">
How to fix RESOURCE_SEMAPHORE_QUERY_COMPILE waits?
1. Add additional memory to SQL Server.
2. Reduce the number of compile and recompiles happening in SQL Server.
3. Threshold for the gateways are dynamic (except for small gateway) and therefore memory pressure occurs from other sources (Internal to SQL Server or system wide) reduces the amount of memory available for compiles and Queries are throttled to higher gateways sooner. Make sure SQL Server is not starving for memory.
4. Identify the queries which are consuming large compile memory and tune them (CompileMemory in show plan XML query compile can be used).
5. RESOURCE_SEMAPHORE_QUERY_COMPILE waits are very common in 32-bit SQL Server because of virtual address space limitation, so migrate to 64-Bit SQL Server.