SQL Server等待事件—RESOURCE_SEMAPHORE_QUERY_COMPILE


等待事件介紹

 

關於等待事件RESOURCE_SEMAPHORE_QUERY_COMPILE,官方的介紹如下:

 

       Occurs when the number of concurrent query compilations reaches a throttling limit. High waits and wait times may indicate excessive compilations, recompiles, or uncachable plans.

 

該等待事件在並發查詢編譯的數量達到閥值限制時出現。 等待時間較長或等待次數較多可能表明編譯、重新編譯或不能緩存的計划過多

 

 

等待事件分析

 

內存授予的等待類型叫做RESOURCE_SEMAPHORE.在理解這個等待事件前,我們先來了解一下查詢內存授予(query memory grant),它是用於在排序或連接時存儲臨時數據的服務器內存的一部分。查詢在實際執行前需要先請求保留內存,所以會存在一個授予的動作。這樣的好處是提高查詢的可靠性和避免單個查詢占用所有的內存。

 

SQL Server在收到查詢時,會執行3個被定義好的步驟來返回用戶所請求的結果集。

  

 

1. 生成編譯計划(compiled plan)。它包括各種邏輯指令,如怎么聯接數據行。

2. 生成執行計划(execution plan),它包含將編譯計划中的各種邏輯引用轉換成實際的對象的指令和查詢執行的跟蹤機制。

3. 從指令樹的頂端開始執行。

 

生成編譯計划是件開銷較大的事情,因為它需要在數以百計的編譯計划中找出較優的一個。它的時間通常很短,因為優化器會在找到最優的編譯計划后便馬上釋放內存。編譯主要使用內存和CPU資源。缺少可用內存可能會導致編譯延遲和得到非最優的編譯計划。    

 

 

當SQL Server創建編譯計划時,會計算兩個參數:必須內存(Requeried memory)和額外內存(Additional memory)。

  

  必須內存:執行排序和哈希聯接所需的最少內存。這部分內存是必須的,它用來創建處理排序和哈希所需要的內部數據結構。

  額外內存:存儲所有臨時數據行所需的內存。它的大小由基數評估(Cardinality estimate,如行數和行大小)決定。額外,顧名思義在缺少這部分內存時,將會將臨時數據行存到硬盤上,並不會導致查詢失敗。一個查詢的額外內存大小如果超過預設的限制,它實際得到的內存量並不一定會跟請求量一樣。

 

例如,對行大小為10byte的100萬行數據進行排序,此查詢的必須內存為為512KB(此值是SQL Server處理一個排序操作創建內部數據結構所需的最小內存量)。為了存儲所有數據行,額外內存可能是10MB。

 

  當編譯計划中含有多個排序和聯接操作時,額外內存的計算就變得復雜了。因為SQL Server要考慮所有操作符如何高效地使用內存。可以查看ShowPlan XML中的<MemoryFractions>標記部分內容,獲取更多內存使用的信息

 

RESOURCE_SEMAPHORE_QUERY_COMPILE等待事件一般是查詢正在等待授予內存以開始進行編譯時發生。編譯內存來自緩沖池(buffer pool),並需要保留足夠的時間以完成編譯過程。 對於多個並發編譯而言,占用太多內存頁可能會導致內存壓力。 為了緩解這種情況,SQL Server啟動編譯過程,確定哪些查詢需要大量的頁面,並迫使某一些查詢會話等待。 同樣,如果內存壓力已經存在,SQL Server將限制可以同時編譯的資源密集型查詢的數量。

 

  如果你的數據庫經常看到這種等待事件或此等待類型過多,那么你的數據庫可能會有太多內存密集型查詢(大型查詢),或者其他進程可能正在從緩沖池中竊取內存頁面.

 

 

減少等待事件方案

 

 

  1. Decrease query complexity 降低查詢語句的復雜度。

 

  1. Appropriate indexing could reduce plan complexity  合理創建索引減少執行計划復雜度

 

  1. Improve plan reuse (therefore compilation can be avoided)  改善執行計划重用(因此可以避免編譯)

 

  1. kill掉一些糟糕的SQL語句(內存資源密集型SQL),當然這個要看是否可行。

 

 

 

個人曾遇到過這樣一個案例,由於過度靈活設計,導致很多報表需要在SQL中大量關聯相關表,更糟糕的是,由於開發人員大量使用視圖,尤其是還存在視圖嵌套視圖的情況,所以在這樣一個系統中,一些查詢語句往往需要授予大量的內存,尤其是當出現一個或一些寫的很糟糕的SQL語句時,就會經常看到一些會話處於RESOURCE_SEMAPHORE_QUERY_COMPILE的等待狀態,而且當大量會話處於RESOURCE_SEMAPHORE_QUERY_COMPILE等待時,還有一個特殊現象就是活動的會話數量會彪增,此時,可以找到消耗內存最多的SQL,然后Kill掉后,活動的會話就會立即降下來。下面就是我遇到案例的一個截圖。

 

SELECT mg.granted_memory_kb, mg.session_id, t.text, qp.query_plan 
FROM sys.dm_exec_query_memory_grants AS mg
CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS t
CROSS APPLY sys.dm_exec_query_plan(mg.plan_handle) AS qp
ORDER BY 1 DESC OPTION (MAXDOP 1)

clip_image001

 

另外,內存緊張也會導致RESOURCE_SEMAPHORE_QUERY_COMPILE的出現的概率增加,那么是否增加內存就有效解決RESOURCE_SEMAPHORE_QUERY_COMPILE等待事件呢?答案是否定的,但是能緩解。如下描述:

 

     This wait occurs when queries cannot be compiled due to the amount of compile memory currently available. This mostly occurs due to large queries requiring an excessive amount of memory. SQL Server caps the amount of complex queries that can be compiled at once, so increasing the memory allocation will not solve the problem effectively (it will only increase the amount of memory that can be allocated, not the number of queries)

 

 

參考資料:

 

https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql

https://documentation.red-gate.com/sm4/working-with-overviews/using-performance-diagnostics/list-of-common-wait-types/resource_semaphore_query_compile

https://www.sqlskills.com/help/waits/resource_semaphore_query_compile/

https://blogs.msdn.microsoft.com/support_sql_france/2012/02/07/sql-server-compilation-gateways-and-resource_semaphore_query_compile/

https://blogs.msdn.microsoft.com/sqlqueryprocessing/2010/02/16/understanding-sql-server-memory-grant/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM