стараться никогда не зацикливаться, работать с наборами данных.
Вы можете вставлять, обновлять, удалять несколько строк одновременно. здесь в качестве примера вставка нескольких строк:
INSERT INTO YourTable
(col1, col2, col3, col4)
SELECT
cola, colb+Colz, colc, @X
FROM ....
LEFT OUTER JOIN ...
WHERE...
вы даже можете вставить в несколько таблиц в одном выражении:
INSERT INTO YourTable
(col1, col2, col3, col4)
OUTPUT INSERTED.PK, Inserted.Col2
INTO OtherTable (ColA, ColB)
SELECT
cola, colb+Colz, colc, @X
FROM ....
LEFT OUTER JOIN ...
WHERE...
Когда вы смотрите на цикл, посмотрите, что он сделал внутри. Если он просто вставляет / удаляет / обновляет, переписать, чтобы использовать отдельные команды. Если есть IF, посмотрите, могут ли они быть операторами CASE или условиями WHERE для вставок / удалений / обновлений. Если это так, удалите цикл и используйте команды set.
Я взял циклы и заменил их командами на основе набора и сократил время выполнения с минут до нескольких секунд. Я взял процедуры со многими вложенными циклами и вызовами процедур и сохранил циклы (было невозможно использовать только вставки / удаления / обновления), но я убрал курсор, и увидел меньше блокировок / блокировок и значительное повышение производительности. Вот два метода зацикливания, которые лучше, чем зацикливание курсора ...
если вам нужно выполнить цикл, над набором сделайте что-то вроде этого:
--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
--just some example of some odd task that requires a loop
set @msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(@hostname) + ' '
+ 'testing "'
print @msg
--EXEC (@msg) --<<will not actually send the messages
--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 --use a table @variable depending on the number of rows to handle
(
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
--just some example of some odd task that requires a loop
SELECT @msg='exec master.dbo.xp_cmdshell "net send '
+ RTRIM(hostname) + ' '
+ 'testing "'
FROM #Rows
WHERE RowID=@From
print @msg
--EXEC (@msg) --<<will not actually send the messages
END