2009-09-15 6 views
0

Dans SQL 2008, j'ai ce facile mais-bad-écriture sp qui fonctionne:Optimise pour la vitesse d'une simple procédure stockée

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 

Je sais: je dois éviter les curseurs, donc je suis assez sûr que cela peut être fait de façon très appropriée.

J'ai essayé avec une seule requête de mise à jour:

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) 

Mais c'est vraiment mal, parce que les select renvoie plus d'une ligne.

Je me sens mal avec ceci, parce que c'est censé être facile pour moi, mais je ne peux pas trouver la requête équivalente.

Des suggestions?

Merci d'avance.

Répondre

3

Il existe de nombreuses solutions à ce problem-- voir this article quelques options. Voici une façon: utiliser une table dérivée.

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; 

Avertissements:

  • Attendez-vous que la table CapacidadesZonas est disponible pour une application en direct alors que la mise à jour se passe? Si c'est le cas, vous pouvez avoir un problème de verrouillage ou de perf, car SQL peut verrouiller toute la table pour la mise à jour de chaque ligne. Si tel est le cas, envisagez d'effectuer votre mise à jour par lots (par exemple, 1 000 lignes chacune). UPDATE TOP facilite le traitement par lots.
  • Parfois, SQL sélectionne un plan sous-optimal pour les requêtes de ce type. il peut être plus rapide de charger une table temporaire (comme dans la solution d'astander ci-dessus, mais en utilisant une table temporaire au lieu d'une table var) que d'essayer de faire la mise à jour en une seule requête. Si vous faites cela, n'oubliez pas de vous assurer qu'il y a un index sur (IDArticulo, NumZona) sur la table temporaire avant de faire votre mise à jour.
+0

Justin: Tu es mon héros! Non seulement tu me donnes la meilleure réponse mais avec des références et des mises en garde possibles. La table va être petite en lignes (cent), et sera mise à jour avant d'apparaître sur l'interface, donc je pense qu'il n'y aura pas de problème de performance. Juste une petite note: dans le script, j'avais besoin de changer le "SUM (s.Cantidad)" pour un "s.Ocupado". –

1

Essayez:

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 
+0

Il n'y a pas de colonne NumZona dans la table ArticulosTickets. Et j'obtiens une erreur de syntaxe dans le GROUP BY. Mais cela me donne l'indice d'utiliser la même table FROM. –

+0

Désolé, sans schéma, il est difficile de vérifier qu'il fonctionnera. – Mitch