更换光标有哪些不同的方法?

时间:2009-06-08 21:10:07

标签: sql-server cursor

我想知道您在现有代码中替换SQL Server游标的经验,或者您如何解决程序人员使用游标解决的问题,并将其设置为基于。

光标用于解决的问题是什么?你是如何更换光标的?

4 个答案:

答案 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时,上一季度的运行总计结转。

最初,我使用游标执行此操作,从功能角度来看,这符合业务要求。从技术的角度来看,它结果是一个显示阻止因为随着数据量的增加,代码花费了指数级的时间。解决方案是使用满足功能要求的相关子查询替换游标,并消除任何性能问题。

希望这有帮助,

比尔