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、事件日志等会显示问题?
提前致谢!
从这里复制我的部分答案...
资源停留的时间取决于您是在本地还是全局声明游标(以及您的环境中的默认值 - 默认值是全局的,但您可以更改它)。
如果游标是全局的,那么它可以在 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)