当您需要循环一组数据时,使用 SQL Server 游标有好处吗?或者使用 WHILE 循环(见下文)也一样。
我问这个问题是因为 WHILE 循环看起来更清晰、更容易理解。
-- loop through a table
DROP TABLE IF EXISTS #LoopingSet;
CREATE TABLE #LoopingSet (RowID INT IDENTITY(1,1), DatabaseName sysname);
INSERT INTO #LoopingSet (DatabaseName) SELECT [name] FROM sys.databases WHERE database_id > 4 ORDER BY name;
DECLARE @i INT = (SELECT MIN(RowID) FROM #LoopingSet);
DECLARE @n INT = (SELECT MAX(RowID) FROM #LoopingSet);
DECLARE @DatabaseName sysname = '';
WHILE (@i <= @n)
BEGIN
SELECT @DatabaseName = DatabaseName FROM #LoopingSet WHERE RowID = @i;
PRINT @DatabaseName; -- do something here
SELECT @i = MIN(RowID) FROM #LoopingSet WHERE RowID > @i;
END;
您在这里展示的实际上是光标的工作原理。您只是用一组 SQL 语句重复了游标的内部工作原理。
我在这里看到的第一个问题是源表可以有索引,一旦将记录集放入临时表中,就会丢失它们。游标将使用源表的原始索引。但您将无法再访问它。
您需要在 上创建索引
RowID
。SQL Server 不会identity
自动在字段上创建索引(它可能应该,但没有)。所以你需要自己做。这是我在您的示例代码中看到的唯一错误。另外,我希望您的代码会出现轻微的性能损失(与游标相比),但这只是因为游标已经编译/优化,并且您的代码在临时表上有两个独立的选择语句。很难说性能损失有多少,但你会遇到的。
但总的来说 - 这就是光标的工作原理。所以你可以在你的代码中使用它。
但如果我是你的队友 - 我会把它重构回光标。主要是为了符合“标准 SQL 处理方法”。光标的语法并不难,在任何维护过程中您都会立即看到“啊哈,这是光标!”。另一方面,您的代码必须被阅读和思考,以识别这里实现的算法。
可能存在循环(RBAR)是唯一选择的情况。可能存在需要循环遍历表的每一行之类的要求。在这种情况下,我们可以使用 Cursor 而不是 While Loop。
另外,如果涉及数百万数据,则性能方面的 Cursor 性能优于 While
了解游标,它们的类型,锁定,范围等。它很容易使用和理解。使用适合您要求的游标类型,锁定范围将提高性能。
Paul White也已经解释了语法。这就是我的意思。