T-SQL。更好的方法:先加入然后组或组再加入

时间:2019-03-23 19:18:05

标签: sql sql-server tsql

我有2张桌子:

订单:

IdProduct (what is ordered - FK to Product table)
Price  (what is the total price for offer)
Piece  (i.e. count - how many products are ordered?) 

产品

Id
Name

有2条SQL语句以最优惠的价格返回产品:

声明1:

SELECT 
    p.Name,
    MIN (Price / Piece) AS MinPrice
FROM 
    [ORDER] o
JOIN 
    Product p ON IdProduct = p.Id
GROUP BY
    p.Name

声明2:

SELECT p.Name, t.MinPrice 
FROM
    (SELECT IdProduct, MIN(Price/Piece) AS MinPrice 
     FROM [Order] 
     GROUP BY IdProduct) t 
JOIN 
    Product p ON p.Id = t.IdProduct

我在Microsoft SQL Server Management Studio中研究了执行计划,尽管我有以下几点观察,但它们看起来非常相似:

  1. 为什么第一个计划使用[order by name]指令?即使我不使用T-SQL Order指令

  2. ,输出的产品名称也按“ asc”排序
  3. 此隐式“按名称asc排序”会减慢第一个sql的速度。当我在第二个sql中添加“按名称asc排序”时,它们的执行计划成本相同。

  4. 我猜因为以下原因,sql#2应该胜过#1:

    a)。它按PK(即整数)而不是按名称(具有nvarchar列类型,并且不进行索引)分组。 b)。仅在将应该最大化性能的第一个表分组后才连接表(相比之下,如第一个sql预期的那样,将全部2个表连接起来)-但是执行计划仍显示相同的估计执行成本。

您希望使用哪种SQL语句,为什么?也许您有自己的SQL语句版本?

1 个答案:

答案 0 :(得分:0)

我个人更喜欢陈述2。我的理由与您期望的完全不同。

您是否意识到自己的2条语句不是为了返回相同的结果而构建的?

第一个查询不会按产品对记录进行分组,而是按产品名称对记录进行分组。在大多数数据库中,称为name的列从不唯一。因此,两个GROUP BY是不相等的(也许您的测试数据会发生使两个结果相同,但这只是运气。)

这是应该写的:

SELECT 
    p.Name,
    MIN (Price / Piece) AS MinPrice
FROM 
    [ORDER] o
JOIN 
    Product p ON IdProduct = p.Id
GROUP BY
    IdProduct, p.Name /* GROUP BY PK on Product */

恕我直言,第二种语法可以很好地防止此类错误。我建议您使用它。
当您使用具有100多个表而不是您自己创建和填充的2个表的旧数据库时,这将为您省去一些麻烦,更不用说第一个语句似乎可以正常工作很长时间了,直到最后,Product.name变得不唯一。

顺便说一句,隐式order by暗示它没有使用PK列。它不会减慢您的查询速度。它正在订购记录以准备GROUP BY


PS:要回答有关性能的问题,您的第二条语句与我写的第二条语句应该非常相似(这要归功于查询计划器)。
有时我看到第一个陈述要慢得多,但从来没有比第二个陈述要显着快(如果存在例外,它们对我来说很罕见,所以错过了它们)。

PPS:由于您汇总了Product中的数据,因此在WHERE中的字段上添加Order可能会使性能变得更复杂。
恐怕这是您每次开发新查询时都必须尝试的事情。