我想知道您在现有代码中替换SQL Server游标的经验,或者您如何解决程序人员使用游标解决的问题,并将其设置为基于。
光标用于解决的问题是什么?你是如何更换光标的?
答案 0 :(得分:7)
尝试永远不要循环,处理数据集。
您可以一次插入,更新,删除多行。这里是一个多行的示例插入:
INSERT INTO YourTable
(col1, col2, col3, col4)
SELECT
cola, colb+Colz, colc, @X
FROM ....
LEFT OUTER JOIN ...
WHERE...
查看循环时,看看它内部做了什么。如果只是插入/删除/更新,请重写以使用单个命令。如果有IF,请查看这些是否可以是插入/删除/更新的CASE语句或WHERE条件。如果是这样,请删除循环并使用set命令。
我已经接受了循环并用基于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
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
答案 1 :(得分:4)
我用WHILE循环替换了一些游标。
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'
答案 2 :(得分:2)
嗯,通常用于程序编程的app dev会出于习惯 - 尝试以程序方式执行所有操作,即使在SQL中也是如此。
大多数情况下,带有正确参数的SELECT可能会这样做 - 或者您正在处理UPDATE语句。
关键在于:您需要开始考虑设置操作并告诉您的RDBMS您想要做什么 - 而不是如何逐步完成。
很难给出一个“正确”的答案.....你几乎必须用一个具体的例子来展示它。
马克
答案 3 :(得分:0)
我编写了一些代码,用于计算与给定年份相关的财务数据的运行总计。在每个季度,我必须将当前季度的值添加到运行总计中,同时适当地处理NULL,以便当前季度的值为NULL时,上一季度的运行总计结转。
最初,我使用游标执行此操作,从功能角度来看,这符合业务要求。从技术的角度来看,它结果是一个显示阻止因为随着数据量的增加,代码花费了指数级的时间。解决方案是使用满足功能要求的相关子查询替换游标,并消除任何性能问题。
希望这有帮助,
比尔