【问题标题】:Optimize for speed a simple stored procedure优化简单存储过程的速度
【发布时间】:2009-09-15 06:48:10
【问题描述】:

在 SQL 2008 中,我有这个简单但写得不好的 sp 有效:

ALTER PROCEDURE [dbo].[paActualizaCapacidadesDeZonas]
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @IdArticulo AS INT
    DECLARE @ZonaAct AS INT
    DECLARE @Suma AS INT

    UPDATE CapacidadesZonas SET Ocupado=0

    DECLARE csrSumas CURSOR FOR
         SELECT AT.IdArticulo, T.NumZona, SUM(AT.Cantidad) 
         FROM ArticulosTickets AT 
              INNER JOIN Tickets T ON AT.IdTicket = T.IdTicket
         GROUP BY AT.IdArticulo, T.NumZona

    OPEN csrSumas

    FETCH NEXT FROM csrSumas INTO @IdArticulo, @ZonaAct, @Suma

    WHILE @@FETCH_STATUS = 0
    BEGIN

         UPDATE CapacidadesZonas SET Ocupado = @Suma
         WHERE NumZona = @ZonaAct AND IdArticulo = @IdArticulo

         FETCH NEXT FROM csrSumas INTO @IdArticulo, @ZonaAct, @Suma
    END

    CLOSE csrSumas
    DEALLOCATE csrSumas   
END

我知道:我必须避免使用游标,所以我很确定它可以以非常正确的方式完成。

我已尝试使用单个更新查询:

UPDATE CapacidadesZonas SET Ocupado = 
(SELECT SUM(AT.Cantidad) 
 FROM ArticulosTickets AT 
       INNER JOIN Tickets T ON AT.IdTicket = T.IdTicket
     GROUP BY AT.IdArticulo, T.NumZona)

但这确实是错误的,因为选择返回不止一行。

我对此感觉很糟糕,因为它应该对我来说很容易,但我找不到等效的查询。

有什么建议吗?

提前致谢。

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008


    【解决方案1】:

    这个问题有很多不同的解决方案——请参阅this article 了解一些选项。这是一种方法:使用派生表。

    UPDATE CapacidadesZonas SET Ocupado=0 WHERE Ocupado <> 0;
    
    UPDATE CapacidadesZonas 
    SET Ocupado = SUM(s.Cantidad)
    FROM CapacidadesZonas C INNER JOIN 
    (
    SELECT T.NumZona, AT.IdArticulo, SUM(AT.Cantidad) as Ocupado
        FROM ArticulosTickets AT 
        INNER JOIN Tickets T ON AT.IdTicket = T.IdTicket
        GROUP BY AT.IdArticulo, T.NumZona
    ) s ON s.NumZona = C.NumZona AND s.IdArticulo = C.IdArticulo;
    

    注意事项:

    • 您是否希望 CapacidadesZon​​as 表在更新期间可供实时应用程序使用?如果是这样,您可能会遇到锁定或性能问题,因为 SQL 可能会锁定整个表以更新每一行。如果是这种情况,请考虑分批进行更新(例如,每次更新 1,000 行)。 UPDATE TOP 使批处理变得容易。
    • 有时 SQL 会为此类查询选择次优计划。加载临时表(如上面的 asstander 解决方案,但使用临时表而不是表 var)可能比尝试将更新作为单个查询来更快。如果您这样做,请记住在进行更新之前确保临时表上的 (IDArticulo, NumZona) 上有一个索引。

    【讨论】:

    • 贾斯汀:你是我的英雄!您不仅给了我最好的答案,而且还提供了参考资料和可能的警告。该表将在行中很小(一百行),并且会在显示在界面上之前进行更新,因此我认为不会有性能问题。只是一个小提示:在脚本中,我需要将“SUM(s.Cantidad)”更改为“s.Ocupado”。
    【解决方案2】:

    试试:

    UPDATE cz
    SET Ocupado = SUM(AT.Cantidad)
    FROM CapacidadesZonas as cz
    INNER JOIN ArticulosTickets AT ON cz.numZona = at.numZona and cz.IDArticulo = at.IDArticulo
    INNER JOIN Tickets T ON AT.IdTicket = T.IdTicket
    GROUP BY AT.IdArticulo, T.NumZona
    

    【讨论】:

    • ArticulosTickets 表中没有 NumZona 列。我在 GROUP BY 中遇到语法错误。但这给了我使用同一个 FROM 表的线索。
    • 抱歉,没有架构,很难验证它是否会运行。
    猜你喜欢
    • 2019-12-17
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 2018-04-03
    相关资源
    最近更新 更多