如何通过 SQL 查询提高订单的性能

时间:2021-03-22 09:49:38

标签: sql sql-server sql-order-by

我有一个 SQL Server 数据库,其中包含表 ProductProductSpecificationProductRetailer。为了收集查询所需的所有信息,我运行以下命令

SELECT        
    pr.ProductId AS Id, p.Name, p.Category, p.Code, ps.Material, 
    p.Brand, ps.Collection, ps.Colour, ps.SubCollection, ps.SurfaceType, 
    MIN(pr.Price) AS LowestPrice, p.ImageUrl, COUNT(pr.Price) AS DealCount
FROM            
    dbo.ProductRetailer AS pr 
INNER JOIN
    dbo.Product AS p ON p.Id = pr.ProductId 
INNER JOIN
    dbo.ProductSpecification AS ps ON p.Id = ps.ProductId
GROUP BY 
    pr.ProductId, p.Name, p.Category, p.Code, ps.Material, p.Brand, 
    ps.Collection, ps.Colour, ps.SubCollection, ps.SurfaceType, p.ImageUrl

在很多情况下,我想按 LowestPrice 订购,但是尽管只有不到 2000 条记录,但我发现查询可能需要长达 45 秒。使用 order by 时,有什么方法可以提高此查询的速度?

附上执行计划 https://www.brentozar.com/pastetheplan/?id=Sy0eWEvN_

在输出上设置统计 IO

<块引用>

(1047 行受影响) 表“工作台”。扫描计数0,逻辑读0,物理读0,预读184,lob逻辑读0,lob物理读0,lob预读0。 表“产品零售商”。扫描计数1064,逻辑读2332,物理读7,预读1,lob逻辑读0,lob物理读0,lob预读0。 表“产品规格”。扫描计数 0,逻辑读 4998,物理读 20,预读 9,lob 逻辑读 0,lob 物理读 0,lob 预读 0。 表“产品”。扫描计数 1,逻辑读 368,物理读 56,预读 313,lob 逻辑读 0,lob 物理读 0,lob 预读 0。

(1 行受影响)

完成时间:2021-03-23T09:17:26.7989169+00:00

3 个答案:

答案 0 :(得分:2)

您可以按如下方式重新编写查询,以消除按所有列分组并使用 apply()

这可能会为您提供更好的执行计划,但是如果没有看到您的实际计划和表上的索引策略,就很难确定。

select pr.ProductId as Id, p.[Name], p.Category, p.Code, 
    ps.Material, p.Brand, ps.[Collection], 
    ps.Colour, ps.SubCollection, ps.SurfaceType,
    pr.LowestPrice,  p.ImageUrl, pr.DealCount
from dbo.Product as p
join dbo.ProductSpecification as ps on ps.ProductId = p.Id
outer apply (
    select Min(pr.Price) as LowestPrice, Count(pr.Price) as DealCount
    from dbo.ProductRetailer as pr 
    group by pr.ProductId
    where pr.ProductId = p.Id
)pr

编辑

您的问题的答案在于您的执行计划。

查询读取的数据量很小,只有60兆。计划的 sort 运算符仅溢出到磁盘的少数行,这表明它没有收到足够高的内存授权。

整个查询只被授予 512K,该计划告诉您为什么需要这么长时间。实际查询耗时 4 秒,请参阅下方计划的 SSMS 输出。

您的 SQL Server 处于内存压力之下,仅此一项就等待了 25 秒。默认的最小授予内存为 1024k,但您的查询仅收到 512k。这表明有人一直在摆弄他们不理解的设置:)

enter image description here

答案 1 :(得分:0)

您可以尝试创建临时表(这将有您的内部联接的结果),然后在临时表上执行 order by。

答案 2 :(得分:0)

对于几千条记录,您的查询不应花费 45 秒。

您首先需要的是 device.name.minsize=4 device.name.maxsize=8 中使用的列的索引:

  • join
  • ProductRetailer(productid, price)

可能还有其他方法可以提高查询效率,但这就是开始。