忘记关闭和取消分配光标会发生什么?

Mik*_*ike 31 t-sql sql-server cursor

将光标保持打开被称为不良做法.但是当你忘记关闭和/或解除分配时会发生什么?它如何影响SQL Server,连接/会话?使用游标的查询,存储过程和触发器的后果是否有任何差异?

Aar*_*and 31

这取决于您是在本地还是全局声明游标(以及您的环境中的默认值 - 默认是全局的,但您可以更改它).

如果光标是全局的,那么它可以在SQL Server中保持"活动"状态,直到在创建它的范围内触及最后一段代码.例如,如果您调用创建全局游标的存储过程,然后调用其他20个存储过程,则当其他20个存储过程正在运行时,游标将继续运行,直到调用者超出范围.我相信它会在会话级别保持活跃,而不是连接级别,但没有彻底测试.如果光标被声明为local,那么它应该只保留在当前对象的范围内(但同样,这是理论上的,我还没有进行大量的低级内存测试来确认).

但是,一般概念应该是:当你完成某些事情时,就这么说.

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

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)

但是,你有多少游标清理这种语法是一个问题?如果你的系统中有数百个游标,那对我来说无疑是一个红旗.

编辑

作为附录,我只想澄清一下,游标本身并不坏.但是,它们经常被误用和滥用 - 在可以实现更高效,基于集合的解决方案的情况下实现,但负责编写查询的人只能在程序上进行思考.游标有意义的几个案例:

  • 运行总计.在我的测试中,游标会删除所有基于SQL 2012之前的基于集合的解决方案(至少是那些记录和支持的解决方案).
  • 各种管理任务,例如,为表中的每一行或每个表或数据库调用存储过程.
  • 当基于集合的替代方案非常复杂,或者任务是一次性的.


Dir*_*irk 6

不关闭游标将使其保持锁定在它所在的行上.即使关闭后,引用仍保留在光标正在使用的数据结构中(因此可以重新打开)这些结构是特定于SQL服务器的(所以它不仅仅是内存空间或句柄等)并且取决于光标实际上是什么这样做,但它们通常是临时表或查询结果集.

不解除分配AFAIK只与性能有关.上述资源将保持分配状态,从而对服务器性能产生负面影响.

从(打开或关闭但未解除分配)游标分配的资源将保持分配,直到会话(或连接)关闭

  • 谢谢,德克。正如亚伦在他的回答中注意到的那样,游标释放行为取决于游标是本地的还是全局的。正如[MSDN](http://msdn.microsoft.com/en-us/library/ms180169.aspx)中所述,当超出范围时,本地游标将自动释放。我感兴趣的是,除了表锁之外,未释放的游标还会泄漏哪些资源。 (2认同)

Ecl*_*ses 6

"游标变量不必显式释放.当变量超出范围时,该变量被隐式释放."

参考:http://msdn.microsoft.com/en-us/library/ms188782.aspx