Sql 组中的标量子查询是错误的做法吗?

Sql 组中的标量子查询是错误的做法吗?,sql,sql-server,nested-select,Sql,Sql Server,Nested Select,我有这个疑问。是否应避免嵌套选择?有更好的办法吗 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

我有这个疑问。是否应避免嵌套选择?有更好的办法吗

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;

您正在SELECT子句中使用一个子查询,我发现它在这里非常合适

表格BE________________________________________。如果您使用了联接,我就不会看到每个xIdBe只有一个BE_Commercial


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

如果插入大量数据,当前查询的性能会很差

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

在WHERE、JOIN、GROUP BY中应避免使用标量UDF。它的性能类似于RBAR。它将针对每一行执行

您可以使用内联TVF并在内部联接条件中使用它,而不是交叉应用。 或者,如果您使用的是交叉应用,则将TVF逻辑写入交叉应用本身

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

您也应该避免子查询。使用左连接代替。 联接比子查询性能更好

在您的查询中,ROW_编号与ORDER BY resIdOf的用法是什么。我看不到它在INSERT中使用。如果确实如此,那么您可以避免使用昂贵的窗口函数

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


然后你可以一个接一个地进行更改。每一步都会有所改进。

我不喜欢使用聚合的相关子查询。聚合条件可能很棘手,因为相关条件需要引用聚合后的值

事实上,相关子查询可能非常有用,但逻辑通常使用左连接实现

更重要的是,重写它们非常简单。因此:

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;
从性能角度来看,这与查询不完全相同,因为连接发生在聚合之前,并且有一个额外的聚合键。但是,我认为这对性能的影响很小,因为它已经在进行聚合了


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

可能重复的可能重复的可能重复的可能重复的可能重复的可能重复的是标量子查询吗?Thx,我感谢您的意见。BE_Numero_BE是PK,所以返回的行数应该相同。@LudovicAubert。如果相关子查询有效,则最多返回一行。我不希望这会成倍增加行数。它看起来像是一个引用表的联接。我的意思是,如果不是唯一的,左联接可能会对行进行多路复用。是的,所以你在这篇文章中的查询和我在Q中的查询都是等价的。
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;