DEALLOCATE CURSOR 之前的 RETURN 语句

div*_*ius 6 sql-server-2008 stored-procedures t-sql

关于在 SQL Server 2008 存储过程中将 Cursors 与 RETURN 结合使用的问题

考虑这个例子:

CREATE PROCEDURE [dbo].[test]
    @ReturnEarly BIT = 0
AS
BEGIN
    SET NOCOUNT ON

    SELECT 1 AS Result INTO #Test

    DECLARE @Result INT, @HasResult INT = 1

    DECLARE TestCursor CURSOR FOR 
        SELECT Result
        FROM #Test
        WHERE Result = 0

    OPEN TestCursor
    FETCH NEXT FROM TestCursor INTO @Result

    IF (@@FETCH_STATUS <> 0)
    BEGIN
        IF (@ReturnEarly = 1)
            RETURN 0
        ELSE 
            SET @HasResult = 0
    END

    CLOSE TestCursor
    DEALLOCATE TestCursor

    DROP TABLE #test --technically superflous

    IF (@HasResult = 0)
        RETURN 0
    ELSE
        RETURN 1 -- in reality many more checks on the actual results
END
GO

-- Allow DEALLOCATE CURSOR to be called
DECLARE   @RC int, @ReturnEarly bit
SET @ReturnEarly = 1
EXECUTE @RC = [test] @ReturnEarly
PRINT @RC
GO

-- Exit before DEALLOCATE CURSOR is called
DECLARE   @RC int, @ReturnEarly bit
SET @ReturnEarly = 0
EXECUTE @RC = [test] @ReturnEarly
PRINT @RC
GO

DROP PROCEDURE [dbo].[test]
Run Code Online (Sandbox Code Playgroud)

存储过程的两个 EXEC 调用都返回相同的结果。我的问题是:从 Cursor 内部返回是否存在潜在的泄漏?例如,没有用于临时表 (#test)。

奖励:你能指出我建议的文档吗?我的谷歌技能达不到它。

额外奖励:如果有问题,我有什么办法可以找到泄漏的证据吗?也许 dmv、事件日志等会显示问题?

提前致谢!

Aar*_*and 2

从这里复制我的部分答案...

资源停留的时间取决于您是在本地还是全局声明游标(以及您的环境中的默认值 - 默认值是全局的,但您可以更改它)。

如果游标是全局的,那么它可以在 SQL Server 中保持“活动”状态,直到在创建它的范围内触及最后一段代码 - 并且通常可以持续存在,甚至超出范围。例如,如果您调用创建全局游标的存储过程,然后调用其他 20 个存储过程,则游标将在其他 20 个存储过程运行时继续存在,直到调用者超出范围。我相信它将在会话级别而不是连接级别保持活动状态,但尚未对此进行彻底测试。如果游标被声明为本地游标,那么它应该只保留在当前对象的范围内(但同样,这是理论上的,我还没有进行广泛的低级内存测试来确认)。我不知道有任何 DMV 可以单独显示此用法,或者即使在全局级别上您可以检测 DMV 中的内存更改,但这些更改可能不会经常更新以反映任何微秒的事实。

不过,一般概念应该是:当你完成某件事时,就说出来。我相信有多种方法可以编写代码,以便RETURN不必在光标内发生这种情况,并且可能有多种方法可以重新编写代码以消除光标。

为了使我的光标尽可能高效,我总是使用以下声明:

DECLARE c CURSOR
  LOCAL STATIC FORWARD_ONLY READ_ONLY
  FOR SELECT ...
Run Code Online (Sandbox Code Playgroud)

我还听说,如果您仅CLOSE或仅DEALLOCATE如此,则可能会出现内存问题 - 尽管我没有证明或反驳它 - 我总是在完成后同时执行这两个操作:

CLOSE c;
DEALLOCATE c;
Run Code Online (Sandbox Code Playgroud)