【问题标题】:Operator causing tempdb to spill data操作员导致 tempdb 溢出数据
【发布时间】:2021-10-16 21:35:00
【问题描述】:

我有一个下面的查询,这导致排序运算符溢出 tempdb 中的数据,并且很可能是导致我面临的性能问题的原因。

SELECT 
    P_All.Status, P_All.Date, P_All.Year, P_All.Amount, P_All.ID,
    P.ID, 
    A.ID, A.Type_ID, A.Date, A.Amount,
    R.Year, R.Amount, R.Balance, R.Title, R.TOTAL, R.TYPE, R.Date, R.ID,
    O.TYPE, O.Name, O.CITY, 
    D.City, D.Code, D.Zip, D.Address,
    S.Description,
 FROM   
    Pmnt P INNER JOIN Rqst R ON P.Rqst_ID=R.ID
    INNER JOIN Org O ON R.Org_ID=O.ID
    INNER JOIN Pmnt P_All ON R.ID=P_All.Rqst_ID
    LEFT OUTER JOIN Actvty A ON R.ID=A.Rqst_ID
    INNER JOIN Addrs D ON O.Addrs_ID=D.ID
    INNER JOIN Sts S ON O.Sts_ID=Sts.ID
 WHERE
    R.TYPE=N'INITIAL' AND R.Date<{ts '2021-08-13 00:00:00'}
 ORDER BY
    O.TYPE, R.ID

我尝试了一些我在谷歌上找到的东西,但没有一个能消除这​​个警告。

到目前为止我尝试过的事情如下:

  • 使用Exec sp_updatestatsUPDATE STATISTICS Org with fullscan 更新了统计信息(以上所有6 个表格)。
  • 为所有 6 个表创建了涉及此查询中涉及的所有列的索引。 (我对索引很陌生)

谁能帮助我解决这个警告?如果您需要我的其他东西,请随时告诉我。

注意:我在this article 中找到了一种可能的解决方案,将数据库的兼容性级别更新为150,但我担心如果更改它可能会搞砸一些事情。所以,现在我正在寻找一些与索引或查询优化相关的解决方案。

实际的 SQL 查询执行计划 - https://www.brentozar.com/pastetheplan/?id=HJxdkN4et

【问题讨论】:

  • 协助调优的第一件事是使用PasteThePlan提供实际的执行计划
  • 仅供参考,您真的不需要FROM 中的所有括号;它们实际上使您的 SQL 更难遵循,而不是更容易。
  • @Stu 在帖子中添加了计划链接。
  • @Larnu 是的,很抱歉。这是其他人编写的非常古老的代码。现已更新。

标签: sql sql-server sqlperformance


【解决方案1】:

你真的不需要 FROM 中的所有括号

这实际上是一个线索。它表明原作者是一个使用图形查询设计器的菜鸟,所以你应该怀疑这个查询有问题,事实证明确实如此。

以下是计划中的查询等待和执行统计信息:

    <WaitStats>
      <Wait WaitType="MEMORY_ALLOCATION_EXT" WaitTimeMs="18" WaitCount="7171" />
      <Wait WaitType="RESERVED_MEMORY_ALLOCATION_EXT" WaitTimeMs="61" WaitCount="64279" />
      <Wait WaitType="SOS_SCHEDULER_YIELD" WaitTimeMs="358" WaitCount="3705" />
      <Wait WaitType="LATCH_EX" WaitTimeMs="810" WaitCount="149" />
      <Wait WaitType="IO_COMPLETION" WaitTimeMs="38588" WaitCount="10990" />
      <Wait WaitType="ASYNC_NETWORK_IO" WaitTimeMs="117148" WaitCount="1530" />
      <Wait WaitType="CXPACKET" WaitTimeMs="558490" WaitCount="39296" />
    </WaitStats>
    <QueryTimeStats CpuTime="54137" ElapsedTime="156188" />

在 156 秒的经过时间中,有 117 秒正在等待向客户端发送 420 万行。 Activity 只有 200K 行,其余表很小,不到 100k 行。

但它连接了多个 1 对多关系,这会放大结果大小,并使最终结果大小难以预测(导致溢出)。

所以这是一个重新考虑这个查询的案例。也许您可以在服务器上聚合它而不是将所有结果发送到客户端,或者将其分解为多个查询,这样您就不必为每个 ActvtyPmnt 排序和发送笛卡尔积 @987654324 @。如果 Rqst 有 50 个 Actvtys 和 4 个 Pmnts,则查询将为该 Rqst 返回 200 行。

它还无缘无故地多次加入Pmnt,这无济于事。

【讨论】:

  • 即使删除括号后,我的等待时间也没有任何明显差异。但是用相同的加入子句加入Pmnt 两次对我来说也很奇怪,并且会调查它。不过,您能想出任何可能需要它的原因吗?
  • 不,对我来说它看起来像一个错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多