Оптимизируйте для скорости простую хранимую процедуру - PullRequest
0 голосов
/ 15 сентября 2009

В 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)

Но это действительно неправильно, потому что выборка возвращает более одной строки.

Мне плохо с этим, потому что это должно быть легко для меня, но я не могу найти эквивалентный запрос.

Есть предложения?

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 15 сентября 2009

Существует много разных решений этой проблемы - см. в этой статье , чтобы найти несколько вариантов. Вот один из способов: использовать производную таблицу.

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;

Предостережения:

  • Ожидаете ли вы, что таблица CapacidadesZonas будет доступна живому приложению во время обновления? В этом случае может возникнуть проблема с блокировкой или перфорированием, поскольку SQL может заблокировать всю таблицу для обновления каждой строки. Если это так, рассмотрите возможность обновления в пакетном режиме (например, по 1000 строк в каждой). UPDATE TOP упрощает процесс дозирования.
  • иногда SQL выбирает неоптимальный план для таких запросов. может быть быстрее загрузить временную таблицу (как в решении Astander выше, но с использованием временной таблицы вместо таблицы var), чем пытаться выполнить обновление как один запрос. Если вы это сделаете, не забудьте убедиться, что на временной таблице есть индекс (IDArticulo, NumZona), прежде чем вы сделаете свое обновление.
1 голос
/ 15 сентября 2009

Попробуйте:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...