【问题标题】:How to make this TOP Query fast in SQL Server?如何在 SQL Server 中使这个 TOP Query 快速?
【发布时间】:2018-09-19 09:13:45
【问题描述】:

这是我的查询:

 SELECT top 1 w.WONumber, * FROM TSP_TSR_Job t  left join
 wsm_WorkOrderSchedule w on w.tsrjobid = t.JobId WHERE t.JobID=325809

执行计划:

我尝试过的:

DECLARE @i INT  
SET @i=1  
SELECT TOP (@i) ObjectType='Job',w.WONumber,*
FROM TSP_TSR_Job t
 left HASH  join wsm_WorkOrderSchedule w 
on w.tsrjobid = t.JobId
 WHERE t.JobID=325809 

执行计划: 问题是这两个查询都需要 0:0:1 秒。
wsm_WorkOrderSchedule 中的 2493073 行和 TSP_TSR_Job 中的 524444
brentozar.com/pastetheplan/?id=ByXUickKQ 执行计划

> SQL Server parse and compile time:     CPU time = 0 ms, elapsed time =
> 0 ms.
> 
>  SQL Server Execution Times:    CPU time = 0 ms,  elapsed time = 0 ms.
> Warning: The join order has been enforced because a local join hint is
> used. SQL Server parse and compile time:     CPU time = 5 ms, elapsed
> time = 5 ms.
> 
> (1 row(s) affected) Table 'Workfile'. Scan count 0, logical reads 0,
> physical reads 0, read-ahead reads 0, lob logical reads 0, lob
> physical reads 0, lob read-ahead reads 0. Table 'Worktable'. Scan
> count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob
> logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table
> 'wsm_WorkOrderSchedule'. Scan count 1, logical reads 6, physical reads
> 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob
> read-ahead reads 0. Table 'TSP_TSR_Job'. Scan count 0, logical reads
> 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob
> physical reads 0, lob read-ahead reads 0.
> 
> (1 row(s) affected)
> 
>  SQL Server Execution Times:    CPU time = 16 ms,  elapsed time = 11
> ms. SQL Server parse and compile time:     CPU time = 0 ms, elapsed
> time = 1 ms.
> 
>  SQL Server Execution Times:    CPU time = 1 ms,  elapsed time = 1 ms.

【问题讨论】:

  • 绿色有索引推荐。
  • wsm_WorkOrderSchedule 未命中连接列上的索引。 SSMS 在第二张截图上已经告诉你了。
  • 索引是什么样的?如果缺少正确的索引,尝试更改连接的工作方式将无济于事。 wsm_WorkOrderSchedule.tsrjobidTSP_TSR_Job .JobId 字段应出现在两个表的索引中。
  • 您在两个计划中的 CIX 扫描上都有一个感叹号。详情是什么?
  • 请注意,您的 TOP 1 缺少 ORDER BY 子句,因此每次都可能导致随机输出。

标签: sql-server query-performance


【解决方案1】:

首先,创建一个索引来去除聚集索引扫描:

CREATE NONCLUSTERED INDEX IX_wsm_WorkOrderSchedule_tsrjobid
    ON wsm_WorkOrderSchedule (tsrjobid)
    INCLUDE (WONumber);

另外,更改您的 TSP_TSR_JobId 索引以包含列。查看键查找运算符以找出需要哪些列

【讨论】:

  • 为什么包含WOnumber?
  • @nikhiljain 因为它在您的SELECT 语句中。包含的列包含在索引的叶节点中,对于这种情况非常有用 - 当您只想输出该列而不是通过它查询时。
  • 如果他有一个* 操作符,那也没什么用。
  • @RaduGheorghiu 废话,你说得对。我没有注意到他对两个表都使用了 *,而不仅仅是 TSP_TSR_Job。查询可能必须重写并显示列名。拥有SELECT * 已经被认为是一种非常糟糕的做法。
【解决方案2】:

我建议你在wsm_WorkOrderSchedule 上添加一个非聚集索引(你好像有):

CREATE NONCLUSTERED INDEX NC_wsm_WorkOrderSchedule_tsrjobid 
ON wsm_WorkOrderSchedule (tsrjobid);

通过添加此索引,您将获得针对特定查询的最佳执行计划(您似乎确实需要所有列,如您所说) .

现在,您的期望是您的查询应该花费不到 1 秒的时间(您现在认为它会这样做)。

但实际上,通过查看来自您的 STATISTICS TIME 输出的信息,您的查询只需要大约 18 毫秒执行(并且有一个重要的区别)。

您在屏幕右下角的 SQL Server Management Studio 中大概看到的剩余 1 秒,实际上是数据通过网络和供 SSMS 渲染。

编辑:

如果您对我在哪里提出 18 毫秒感到好奇,只需转到 statisticsparser.com 并在其中发布您的 STATISTICS TIME 和 IO 的文本输出并解析即可。您将按表格很好地直观了解您的时间和其他资源使用情况。

【讨论】:

    猜你喜欢
    • 2015-09-23
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 2011-02-08
    • 1970-01-01
    • 2020-02-10
    相关资源
    最近更新 更多