【发布时间】:2010-09-14 02:18:03
【问题描述】:
我最近的任务是调试电子商务应用程序中的一个奇怪问题。应用程序升级后,网站开始不时挂起,我被派去调试。检查事件日志后,我发现 SQL 服务器在几分钟内写入了大约 200 000 个事件,并显示约束失败的消息。经过多次调试和一些跟踪,我找到了罪魁祸首。我已经删除了一些不必要的代码并对其进行了一些清理,但基本上就是这样
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
事实:
- 只有一个或两个记录匹配第一个选择子句
- DELETE 语句中的 RowCount 表明它已被删除
- WHILE 子句将永远循环
该过程已被重写,以选择应删除的行到临时内存表中,从而解决了眼前的问题,但这确实激发了我的好奇心。
为什么它会永远循环?
澄清:delete不会失败(调试时delete stmt后@@rowcount为1) 澄清 2:SELECT TOP ... 子句是否按任何特定字段排序都无关紧要,因为具有返回 id 的记录将被删除,因此在下一个循环中它应该得到另一个记录。
更新:检查颠覆日志后,我发现了导致此存储过程失控的罪魁祸首提交。我能找到的唯一真正的区别是,之前在 SELECT TOP 1 语句中没有加入,即没有加入,它在没有任何围绕删除的事务语句的情况下工作。似乎是连接的引入使 SQL Server 更加挑剔。
更新说明:brien 指出不需要连接,但我们确实使用了 GoodsForSale 表中的一些字段,但我删除了它们以保持代码简单,以便我们可以专注于手头的问题
【问题讨论】:
-
什么约束失败了?是在 ShoppingCartItem 还是 GoodsForSale 上?
-
看看我的回答,这个问题还没有解决吗?
标签: sql sql-server tsql