【问题标题】:What happens when you forget to close and deallocate cursor?当您忘记关闭和释放游标时会发生什么?
【发布时间】:2012-03-07 16:45:59
【问题描述】:

让光标保持打开状态是一种不好的做法。

  • 但是当您忘记关闭和/或释放它时,会发生什么?
  • 它如何影响 SQL Server、连接/会话?
  • 使用游标的查询、存储过程和触发器的结果有什么不同吗?

【问题讨论】:

    标签: sql-server tsql database-cursor


    【解决方案1】:

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

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

    不过,一般概念应该是:当你完成某事时,说出来。

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

    DECLARE c CURSOR
      LOCAL STATIC FORWARD_ONLY READ_ONLY
      FOR SELECT ...
    

    我还听说如果您只使用 CLOSE 或仅使用 DEALLOCATE 可能会出现内存问题,所以我总是在完成后同时做这两个:

    CLOSE c;
    DEALLOCATE c;
    

    但是,您有多少游标来清理这种语法是个问题?如果您的系统中有数百个游标,那对我来说肯定是一个危险信号。

    编辑

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

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

    【讨论】:

    • 在我使用的数据库中声明的本地游标触发器很少。那些没有关闭,也没有被释放。是错误还是本地游标的正确使用?
    • 不明白您认为哪个部分可能是错误。我建议,很可能所有这些游标都可以被更有效的、基于集合的解决方案所取代,该解决方案根本不涉及游标。但我不知道,因为我不知道触发器的作用。
    • 游标用于在插入和删除的表中的每一行上调用一些存储过程,可能会将其与其他一些表连接起来。
    • 代码质量问题,执行行为没有区别。我还可以提出这样的论点,即万一出现错误,这些语句都不会运行。所以无论如何都不能绝对依赖它们。
    • 查看 Aaron 的文章:sqlperformance.com/2012/09/t-sql-queries/cursor-options 他推荐“LOCAL FAST_FORWARD”(我猜他忘了回来更新 :))
    【解决方案2】:

    “游标变量不必显式释放。当变量超出范围时,它会被隐式释放。”

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

    【讨论】:

    • 释放游标变量与释放游标不同。从同一页:“DEALLOCATE @cursor_variable_name 语句仅删除命名变量对游标的引用。”
    • 是的,你是对的,但是正如官方文档中所写,你不需要释放变量,所以你可以避免使用额外的代码。
    【解决方案3】:

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

    不解除分配 AFAIK 仅与性能有关。上述资源将保持分配状态,因此会对服务器性能产生负面影响。

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

    【讨论】:

    • 您能否说明未释放的游标将保留资源多长时间?以及什么样的资源系统内存/句柄/等等?
    • 用一些附加信息更新了答案
    • 谢谢,德克。正如 Aaron 在他的回答中注意到的那样,游标的释放行为取决于游标是本地的还是全局的。正如MSDN 中所说,当超出范围时,本地游标将自动释放。让我感兴趣的是,除了表锁之外,未释放的游标还会泄露哪些资源。
    猜你喜欢
    • 1970-01-01
    • 2012-09-11
    • 2013-03-11
    • 2011-01-06
    • 1970-01-01
    • 2020-05-05
    • 2011-09-17
    • 2011-08-25
    • 1970-01-01
    相关资源
    最近更新 更多