存储过程耗时超过 10 秒

She*_*llz 3 performance sql-server sql-server-2016 query-performance

我有这个需要 10 多秒才能运行的存储过程。它向应用程序返回一个数据集(文件列表)。有关如何加快速度的任何建议?

有关计划的详细信息。看起来计划中的查询 14 占批处理的 98%。查询 14 中的排序占查询 14 的 62%。

我使用的是 SQL Server 2016。估计的查询计划

这是实际的计划。花了 5 分钟。和 21 秒运行。

Pau*_*ite 7

第一次插入

第一个插入语句的实际计划揭示了一些您应该改进的地方:

第一次插入

  1. 我会OPTION (RECOMPILE)向这个查询添加一个提示。这将允许优化器在考虑变量的运行时值的情况下生成计划。这应该会大大简化计划。
  2. 一旦上面的提示到位,您应该确保Uploads表有一个索引ClientID, UploadCompleteDttm作为前导键。这将提供所需的排序顺序,并在@startdate_local不为空时允许查找。
  3. 索引还应包括FileName, FileUploadID, ProcessErrorText以避免查找。一个示例索引定义是:

    CREATE INDEX IndexName
    ON fileManager.FileUploads (ClientID, UploadCompleteDttm)
    INCLUDE (FileName, FileUploadID, ProcessErrorText);
    
    Run Code Online (Sandbox Code Playgroud)
  4. FilesReceived上的聚集索引扫描看起来非常昂贵。测试了 55 亿行(通过多次扫描)以返回大约 5,000 行。这个成本被残差谓词很好地隐藏了(如Sentry One Plan Explorer 所示):

    扫描属性

  5. 向以键的FilesReceived添加索引FileUploadID。如果该索引已存在,并且在应用了此处列出的先前步骤后扫描仍保留在实际执行计划中FORCESEEK,请在FilesReceived引用上使用提示。你也可以试试OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL'));

第二次插入

跳出我的问题部分是:

计划片段

这对应于代码:

(select count(1)
     from fileManager.FilesReceived fr
      join fileManager.Tracking t on fr.FilesReceivedID = t.FilesReceivedID
     where parentfileid = z.FilesReceivedID) as 'HasChildren'
Run Code Online (Sandbox Code Playgroud)

其余的执行计划相当大,但看起来并不太可怕。OPTION (RECOMPILE)出于与第一次查询相同的原因,我仍会再试一次。

如果这本身不能充分提高性能:我将从查询中删除上面显示的代码片段,将结果行(给出的示例中只有 5,239)持久化在一个单独的临时表中,然后在HasChildren单独的步骤中找到该值。我还将重写 finalINSERT以使用显式TOP (5)子句而不是使用SET ROWCOUNT 5.

确保FilesReceived表在 上有一个索引ParentFileId