J'ai récemment été chargé de déboguer un problème étrange dans une application de commerce électronique. Après la mise à niveau d'une application, le site a commencé à être suspendu de temps en temps et j'ai été envoyé en mode débogage. Après avoir vérifié le journal des événements, j'ai trouvé que le serveur SQL a écrit ~ 200 000 événements en quelques minutes avec le message disant qu'une contrainte avait échoué. Après beaucoup de débogage et quelques recherches, j'ai trouvé le coupable. J'ai enlevé un peu de code inutile et nettoyé un peu, mais essentiellement c'est ilWhile-clause dans T-SQL qui boucle pour toujours
WHILE EXISTS (SELECT * FROM ShoppingCartItem WHERE ShoppingCartItem.PurchID = @PurchID)
BEGIN
SELECT TOP 1
@TmpGFSID = ShoppingCartItem.GFSID,
@TmpQuantity = ShoppingCartItem.Quantity,
@TmpShoppingCartItemID = ShoppingCartItem.ShoppingCartItemID,
FROM
ShoppingCartItem INNER JOIN GoodsForSale on ShoppingCartItem.GFSID = GoodsForSale.GFSID
WHERE ShoppingCartItem.PurchID = @PurchID
EXEC @ErrorCode = spGoodsForSale_ReverseReservations @TmpGFSID, @TmpQuantity
IF @ErrorCode <> 0
BEGIN
Goto Cleanup
END
DELETE FROM ShoppingCartItem WHERE ShoppingCartItem.ShoppingCartItemID = @TmpShoppingCartItemID
-- @@ROWCOUNT is 1 after this
END
Faits:
- Il y a seulement un ou deux dossiers correspondant à la première sélection de la clause
- RowCount de l'instruction DELETE indique qu'il a été supprimé
- la boucle de volonté While clause pour toujours
La procédure a été réécrite pour sélectionner les lignes qui devraient être supprimées dans une table temporaire en mémoire à la place afin que le problème immédiat soit résolu mais cela a vraiment suscité ma curiosité.
Pourquoi boucle-t-il toujours?
Précision: La suppression ne manque pas (@@ rowcount est 1 après la suppression stmt lorsque débogué) Précision 2: Il ne faut pas d'importance si le TOP SELECT ... clause est commandé par n'importe quel champ spécifique puisque l'enregistrement avec l'identifiant retourné sera supprimé ainsi dans la prochaine boucle il devrait obtenir un autre enregistrement.
Mise à jour: Après avoir vérifié les journaux de subversion j'ai trouvé le commit coupable qui a rendu cette procédure stockée pour aller haywire. La seule vraie différence que je peux trouver est qu'il n'y avait auparavant aucune jointure dans l'instruction SELECT TOP 1, c'est-à-dire sans cette jointure, cela fonctionnait sans aucune déclaration de transaction entourant la suppression. Il semble être l'introduction de la jointure qui a rendu le serveur SQL plus pointilleux.
clarification de mise à jour: brien a fait remarquer qu'il n'y a pas besoin de le rejoindre, mais nous faisons réellement utiliser certains champs de la table GoodsForSale mais je les ai enlevés pour garder le code simplement pour que nous puissions concentrer sur le problème hand
Quelle contrainte a échoué? Était-ce sur ShoppingCartItem ou GoodsForSale? – brien
Voir ma réponse, cette question est toujours ouverte? –