关于查询计划中内存“过度授予”的警告 - 如何找出导致它的原因?

Mar*_*lli 18 performance sql-server optimization execution-plan query-performance performance-tuning

我正在运行一个查询,该查询给出有关内存的警告Excessive Grant

使用的表和索引太多,包括复杂的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>
Run Code Online (Sandbox Code Playgroud)

和这个:

<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>
Run Code Online (Sandbox Code Playgroud)

这是查询,尽管您也可以在此处查看带有执行计划的查询

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)
)
Run Code Online (Sandbox Code Playgroud)

这是警告的样子:

在此处输入图片说明

执行计划在这里

我该如何处理这个警告?

正如我之前所说,我正在研究转换。我可以在执行计划中寻找任何可以表明这种过度拨款的可能原因的东西吗?

观察。我说涉及的对象太多,但是,如果可能有助于解决此问题,我可以根据要求在此处添加所需的任何内容。没问题。

Eri*_*ing 23

最常见的两种消耗内存的运算符是:

  • 排序
  • 哈希值

如果计划是并行的,内存需求将增加一定数量,以补偿线程通过行的交换。并行计划不需要整个串行内存授予 * DOP(尽管串行所需内存和 DOP 之间可能存在关系)。完全授权被拆分并(希望)在计划中的所有线程中均匀使用。

在某些情况下,嵌套循环连接也可能要求内存。

内存授权由优化器根据行数和将通过内存消耗运算符的数据大小计算。如上所述,如果计划是并行的,则可能会要求更多。另一个因素是内存消耗操作符可以共享内存。

例如,排序消耗的一些内存可以在数据排序后传递给上游操作符,并且哈希可以在初始构建阶段完成后将内存传递给上游,并且被探测的行开始向上游移动。这可以通过内存分数信息观察到。

在您的计划中,您有三个 Sort 运算符。

坚果

综合起来,优化器认为它需要 2 MB 的内存才能运行而不会溢出到磁盘。它最终只需要 24 KB,因此出现警告。

内存授予错误估计可能来自很多地方。在您的查询中,您有一个变量:@arrivalDate.

不清楚此参数是否在存储过程中,或者您是否在本地调用它。在任何一种情况下,您都可以尝试重新编译提示,以查看是否通过获得不同的基数估计来消除警告。

如果这不起作用,您可能想尝试调整索引,以便不需要单独的排序操作,但这可能比如此少量的内存更值得。

以供参考: