查詢計劃中有關記憶體“過度授予”的警告 - 如何找出導致它的原因?
我正在執行一個查詢,它給出有關記憶體的警告
Excessive Grant
。使用的表和索引太多,包括一個 complex
view
,因此很難在此處添加所有定義。我正在嘗試找出可能導致
Excessive Grant
. 可以轉化嗎?查看執行計劃,我可以看到以下內容:
<ScalarOperator ScalarString="CONVERT(date,[apia_repl_sub].[dbo].[repl_Aupair].[ArrivalDate] as [repl].[ArrivalDate],0)"> <Convert DataType="date" Style="0" Implicit="false"> <ScalarOperator> <Identifier> <ColumnReference Database="[apia_repl_sub]" Schema="[dbo]" Table="[repl_Aupair]" Alias="[repl]" Column="ArrivalDate" /> </Identifier> </ScalarOperator> </Convert> </ScalarOperator>
和這個:
<ScalarOperator ScalarString="CONVERT(date,[JUNOCORE].[dbo].[applicationPlacementInfo].[arrivalDate] as [pi].[arrivalDate],0)"> <Convert DataType="date" Style="0" Implicit="false"> <ScalarOperator> <Identifier> <ColumnReference Database="[JUNOCORE]" Schema="[dbo]" Table="[applicationPlacementInfo]" Alias="[pi]" Column="arrivalDate" /> </Identifier> </ScalarOperator> </Convert> </ScalarOperator>
這是查詢,儘管您也可以在此處查看帶有執行計劃的查詢:
DECLARE @arrivalDate DATEtime = '2018-08-20' SELECT app.applicantID, app.applicationID, a.preferredName, u.firstname, u.lastname, u.loginId AS emailAddress, s.status AS statusDescription, CAST(repl.arrivalDate AS DATE) AS arrivalDate, app.moodleCourseComplete, app.moodleCourseCompleteUpdated, u.loginId, c.countryName FROM app.application AS app JOIN app.applicant AS a ON a.applicantId = app.applicantId JOIN usr.[user] AS u ON u.userId = a.userId JOIN app.ref_applicationStatus AS s ON s.statusCode = app.status JOIN APIA_Repl_Sub.dbo.repl_Aupair AS repl ON repl.JunoCore_applicationID = app.applicationID JOIN app.Country AS c ON c.countryCode = a.nationalityCode WHERE repl.arrivalDate = @arrivalDate UNION ALL ( SELECT app.applicantID, app.applicationID, app.preferredName, app.firstname, app.lastname, app.emailAddress, ap.status, CAST(app.arrivalDate AS DATE) AS arrivalDate, app.moodleCourseComplete, app.moodleCourseCompleteUpdated, app.emailAddress AS loginId, c.countryName FROM JUNOCore.dbo.vw_SelectApplication AS app INNER JOIN JUNOCore.dbo.country c ON c.countryCode = app.nationalityCode INNER JOIN JUNOCore.dbo.application as ap ON ap.applicationID = app.applicationID WHERE arrivalDate = @arrivalDate AND app.applicationID NOT IN (SELECT p4.applicationId FROM APCore.app.application p4) )
這是警告的樣子:
我該如何處理這個警告?
正如我之前所說,我正在研究轉換。我可以在執行計劃中尋找什麼可以表明這種過度授權的可能原因嗎?
觀察。我說涉及的對象太多,但是,如果可能有助於解決此問題,我可以根據要求在此處添加所需的任何內容。沒問題。
最常見的兩種消耗記憶體的運算符是:
- 排序
- 雜湊
如果計劃是並行的,記憶體需求將增加一些以補償執行緒通過行的交換。並行計劃不需要整個串列記憶體授予 * DOP(儘管串列所需記憶體和 DOP 之間可能存在關係)。全部授權被拆分並(希望)在計劃中的所有執行緒中均勻使用。
在某些情況下,嵌套循環連接也可能會要求記憶體。
記憶體授予由優化器根據行數和將通過記憶體消耗運算符的數據大小來計算。如上所述,如果計劃是平行的,它可能會要求更多。另一個因素是消耗記憶體的運算元可以共享記憶體。
例如,排序消耗的一些記憶體可以在數據排序後傳遞給上游操作符,而雜湊可能會在初始建構階段完成後將記憶體傳遞給上游,並且探測的行開始向上游移動。這可以通過記憶體分數資訊觀察到。
在您的計劃中,您有三個排序運算符。
綜合起來,優化器認為它需要 2 MB 的記憶體才能執行而不會溢出到磁碟。它最終只需要 24 KB,因此發出警告。
記憶體授予錯誤估計可能來自許多地方。在您的查詢中,您有一個變數:
@arrivalDate
.目前尚不清楚此參數是否在儲存過程中,或者您是否在本地呼叫它。在任何一種情況下,您都可以嘗試重新編譯提示,以查看是否通過獲取不同的基數估計來消除警告。
如果這不起作用,您可能想要嘗試調整索引,以便不需要單獨的排序操作,但這可能比如此少量的記憶體更複雜。
以供參考:
- 為什麼你調錯儲存過程(局部變數的問題)
- 以正確的方式解決參數嗅探問題:第 1 部分(第一篇文章中提供了其他部分的連結)
- 關於局部變數的另一篇文章