--this looks up each row for every iteration
DECLARE @msg VARCHAR(250)
DECLARE @hostname sysname
--first select of currsor free loop
SELECT @hostname= min(RTRIM(hostname))
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
WHILE @hostname is not null
BEGIN
set @msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(@hostname) + ' '
+ 'testing "'
print @msg
--EXEC (@msg)
--next select of cursor free loop
SELECT @hostname= min(RTRIM(hostname))
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
and hostname > @hostname
END
如果你有一个合理的项目集(不是100,000)循环,你可以这样做:
--this will capture each Key to loop over
DECLARE @msg VARCHAR(250)
DECLARE @From int
DECLARE @To int
CREATE TABLE #Rows
(
RowID int not null primary key identity(1,1)
,hostname varchar(100)
)
INSERT INTO #Rows
SELECT DISTINCT hostname
FROM master.dbo.sysprocesses (NOLOCK)
WHERE hostname <> ''
SELECT @From=0,@To=@@ROWCOUNT
WHILE @From<@To
BEGIN
SET @From=@From+1
SELECT @msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(hostname) + ' '
+ 'testing "'
FROM #Rows WHERE RowID=@From
print @msg
--EXEC (@msg)
END
DECLARE @SomeTable TABLE
(
ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
SomeNumber int,
SomeText varchar
)
DECLARE @theCount int
DECLARE @theMax int
DECLARE @theNumber int
DECLARE @theText varchar
INSERT INTO @SomeTable (SomeNumber, SomeText)
SELECT Number, Text
FROM PrimaryTable
SET @theCount = 1
SELECT @theMax = COUNT(ID) FROM @SomeTable
WHILE (@theCount <= @theMax)
BEGIN
SET @theNumber = 0
SET @theText = ''
SELECT @theNumber = IsNull(Number, 0), @theText = IsNull(Text, 'nothing')
FROM @SomeTable
WHERE ID = @theCount
-- Do something.
PRINT 'This is ' + @theText + ' from record ' + CAST(@theNumber AS varchar) + '.'
SET @theCount = @theCount + 1
END
PRINT 'Done'
declare @PrimaryKey int
/* get first record for looping */
select @PrimaryKey = min(PrimaryKey) from Table
/* it will be null when all records have iterated */
while (@PrimaryKey is not null)
begin
/* do stuff */
/* iterate to next key */
select @PrimaryKey = min(PrimaryKey) from Table where PrimaryKey > @PrimaryKey
end
5条答案
按热度按时间jq6vz3qz1#
尽量不要循环,处理数据集。
你可以插入,更新,删除多行在同一时间.这里在一个例子插入多行:
查看循环时,看看它在里面做了什么。如果只是插入/删除/更新,重写为使用单个命令。如果有IF,看看它们是否是插入/删除/更新的CASE语句或WHERE条件。如果是,删除循环并使用set命令。
我用基于集合的命令替换了循环,将执行时间从几分钟减少到几秒钟;我用许多嵌套循环和过程调用替换了过程,并保留了循环(只使用插入/删除/更新是不可能的),但是我删除了游标,并且看到了更少的锁定/阻塞和巨大的性能提升。这里有两个比游标循环更好的循环方法。
如果你必须循环,在一个集合上做如下操作:
如果你有一个合理的项目集(不是100,000)循环,你可以这样做:
t8e9dugd2#
我用WHILE循环替换了一些游标。
u3r8eeie3#
通常,习惯于过程式编程的应用程序开发人员出于习惯,会尝试过程化地做所有事情,即使是在SQL中。
大多数情况下,带有正确参数的SELECT语句就可以做到--或者您正在处理的是UPDATE语句。
关键是:你需要开始考虑集合操作,告诉你的RDBMS你想做什么--而不是如何一步一步地做。
很难给予一个单一的、“正确的”答案......你几乎必须用一个具体的例子来说明它。
马克
3zwtqj6y4#
我编写了一些代码来计算与给定年份相关的财务数据的累计,在每个季度,我必须将当前季度的值添加到累计中,同时适当地处理NULL,以便当前季度的值为NULL时,上一季度的累计可以结转。
最初,我使用游标来完成此操作,从功能Angular 来看,这满足了业务需求。从技术Angular 来看,这变成了一个障碍,因为随着数据量的增加,代码花费的时间呈指数增长。解决方案是用满足功能需求并消除任何性能问题的相关子查询来替换游标。
希望这能帮上忙,
比尔
nzk0hqpo5#
当(看看我在那里做了什么)问题被问了又回答,我想添加我的响应,以防它会帮助其他人。像许多其他人一样,我转换到while语句,但我想利用我的数据集中现有的主键,而不是计数到结果集的大小。我想出了这个模式,一直运作良好。我对其他人和改进持开放态度。谢谢!