游标 在 SQL 中允许逐行遍历数据集并对每条记录执行特定操作,这类似于编程中的迭代。这对于无法通过单个 SQL 查询实现的复杂逐步逻辑非常方便(例如,具有外部状态变化的逐步计算)。
游标示例:
DECLARE my_cursor CURSOR FOR SELECT id, balance FROM Accounts WHERE isActive = 1; OPEN my_cursor; DECLARE @id INT, @bal DECIMAL(10,2); FETCH NEXT FROM my_cursor INTO @id, @bal; WHILE @@FETCH_STATUS = 0 BEGIN UPDATE Accounts SET balance = @bal * 1.05 WHERE id = @id; FETCH NEXT FROM my_cursor INTO @id, @bal; END CLOSE my_cursor; DEALLOCATE my_cursor;
优点:
缺点和潜在问题:
可以在触发器内部使用游标吗?这可能对数据库性能产生什么影响?
回答和示例: 在触发器内部使用游标是可能的,但极不推荐——每个 DML 操作可能会为每个受影响的行启动游标,这会导致请求和锁定的激增。
CREATE TRIGGER UpdateBalance ON Accounts AFTER INSERT AS DECLARE c CURSOR FOR SELECT id FROM inserted; -- 不好! OPEN c; -- ...
历史
项目:零售订单摘要。 任务是计算库存余量,如果发现批次存在缺陷——后续批次需要通过更新折扣手动重新计算。使用游标遍历批次。后来发现,在多次运行时,线程被阻塞了几个小时,服务器负载呈指数增长,锁定争用导致了故障。
历史
项目:ERP,数据迁移。 在导入处理程序中添加了通过游标处理错误的功能。没有考虑到在 500 万行上,游标的效率比使用基于集合的更新 + CASE 的批处理慢了 40 倍。由于迁移缓慢,截止日期被推迟。
历史
项目:财务公司的账单。 在资金变动表的更新触发器中添加了游标,以计算新的聚合余额。在生产环境中,这导致了“停止世界”——插入即使是一条记录也因为启动嵌套游标在许多行上而减缓了服务的运行。