【问题标题】:Are scalar subqueries in a group by a bad practice?组中的标量子查询是一种不好的做法吗?
【发布时间】:2019-07-19 08:44:14
【问题描述】:

我有这个问题。应该避免嵌套选择吗?有没有更好的办法?

WITH cte(oi, oIdOf) AS (
    SELECT ROW_NUMBER() OVER (ORDER BY resIdOf), resIdOf
    FROM @res
    WHERE resIdOf<>0
    GROUP BY resIdOf    
)
INSERT INTO @fop
SELECT x.xIdOf
        ,x.xIdBe
        ,x.xLgnBe
        ,(SELECT e.BE_Commercial FROM BE_ENLEVEMENT AS e WHERE e.BE_Numero_BE=x.xIdBe)
        ,SUM(x.xCoeff)
FROM cte AS o
CROSS APPLY dbo.ft_grapheOfOrigine(o.oIdOf) AS x
GROUP BY x.xIdOf,x.xIdBe,x.xLgnBe;

【问题讨论】:

标签: sql sql-server nested-select


【解决方案1】:

我不喜欢聚合相关的子查询。聚合条件可能很难正确处理,因为相关条件需要引用聚合后的值

事实上,相关子查询可能非常有用,但逻辑​​通常是使用LEFT JOIN 来实现的。

更重要的是,重写它们真的很简单。所以:

SELECT x.xIdOf, x.xIdBe, x.xLgnBe,
       e.BE_Commercial,
       SUM(x.xCoeff)
FROM cte o CROSS APPLY 
     dbo.ft_grapheOfOrigine(o.oIdOf) AS x LEFT JOIN
     BE_ENLEVEMENT e
     ON e.BE_Numero_BE = x.xIdBe
GROUP BY x.xIdOf, x.xIdBe, x.xLgnBe, e.BE_Commercial;

从性能的角度来看,这与您的查询并不完全相同,因为JOIN 发生在聚合之前,并且还有一个额外的聚合键。但是,我认为这对性能的影响非常小,因为它已经在进行聚合。

如果这是一个问题,您可以使用子查询来获得基本相同的执行计划。

【讨论】:

  • BE_Numero_BE 是PK,所以返回的行数应该是一样的。
  • @LudovicAubert 。 . .如果相关子查询有效,则最多返回一行。我不希望这会增加行数。它看起来像一个引用表的连接。
  • 如果 BE_Numero_BE 不是唯一的,我的意思是 LEFT JOIN 可以乘以行。是的,所以这两个查询(你在这篇文章中的和我在 Q 中的)是等价的。
【解决方案2】:

您在SELECT 子句中使用了子查询,我觉得这里非常合适。

BE_ENLEVEMENT 在此处用作查找表,您可以在其中查找每个选定xIdBeBE_Commercial。如果您改为使用连接,我不会看到每个 xIdBe 只有一个 BE_Commercial

这意味着select子句中的子查询使查询更容易理解,这很好。可读性增强了可维护性。

【讨论】:

  • 谢谢,感谢您的意见。
【解决方案3】:

如果有大量数据插入,您当前的查询将导致性能不佳。

如果它插入几行,比如 10 行,那么你可以忽略它。

Scalar UDF 应避免在WHERE ,JOIN,GROUP BY 中。它执行类似于RBAR。它将针对每一行执行。

您可以使用Inline TVF 并在Inner join 条件下使用它而不是CROSS APPLY。 或者,如果您使用的是 CROSS APPLY,则将 TVF logic 写入 CROSS APPLY 本身。

子查询错误。使用TOP 1是安全的

(SELECT TOP 1 e.BE_Commercial FROM BE_ENLEVEMENT AS e WHERE e.BE_Numero_BE=x.xIdBe)

你也应该避免sub query。请改用LEFT JOINJOIN 比子查询更高效。

ROW_NUMBER() OVER (ORDER BY resIdOf) 在您的查询中有什么用途。我没有看到它在 INSERT 中使用。如果确实如此,那么您可以避免昂贵的 WINDOW Function

您可以使用工具提示截屏或保存现有查询的计划。

然后你就可以一个一个地改变了。每一步都会有改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-24
    • 2016-09-26
    • 2019-09-01
    • 2012-04-28
    • 1970-01-01
    • 1970-01-01
    • 2021-01-10
    • 2015-05-31
    相关资源
    最近更新 更多