使用游标的优点和缺点(在SQL服务器中)

dev*_*747 7 sql-server cursor

我在这里问了一个问题在OLTP数据库中使用游标(SQL服务器)

人们回应说,不应该使用游标.

我觉得游标是非常强大的工具,意味着要使用(我不认为Microsoft支持错误的开发人员使用游标).假设您有一个表,其中一行中的列值取决于同一列的值在上一行.如果是一次性后端处理,您不认为使用游标是可接受的选择吗?

在我的脑海中,我可以想到几个场景,我觉得使用游标不应该感到羞耻.如果你们有其他的感觉,请告诉我.

1>一次性后端处理,用于清除在几分钟内完成执行的错误数据.2>在很长一段时间内运行一次的批处理(类似于一年一次).如果在上述场景中,其他进程没有明显的压力,那么花费额外的时间编写代码来避免使用游标是不合理的?换句话说,在某些情况下,开发人员的时间比对其他任何事情几乎没有影响的流程的执行更重要.

在我看来,这些是你应该认真尝试避免使用游标的一些场景.1>从网站调用的存储过程可以经常被调用.2>每天运行多次并消耗大量资源的SQL作业.

我认为,在不分析手头的任务并实际权衡其他选择的情况下,做出"游标不应该被使用"这样的一般性陈述是非常肤浅的.

请让我知道你的想法.

Aar*_*and 11

在几种情况下,游标实际上比基于集合的等价物更好.总是会想到运行总计 - 查找Itzik的话(并忽略任何涉及SQL Server 2012的内容,它会添加新的窗口函数,在这种情况下为游标提供运行).

人们对游标的一个重大问题是它们执行缓慢,它们使用临时存储等.这部分是因为默认语法是具有各种低效默认选项的全局游标.下次你用光标做一些不需要做的事情UPDATE...WHERE CURRENT OF(我已经能够避免我的整个职业生涯),通过比较这两个语法选项,给它一个公平的动摇:

DECLARE c CURSOR 
    FOR <SELECT QUERY>;

DECLARE c CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY
    FOR <SELECT QUERY>;
Run Code Online (Sandbox Code Playgroud)

实际上,第一个版本表示未记录的存储过程sp_MSforeachdb中的错误,如果任何数据库的状态在执行期间发生更改,则会使其跳过数据库.我随后编写了自己的存储过程版本(参见此处此处),它们都修复了错误(只需使用上面语法的后一版本)并添加了几个参数来控制选择哪些数据库.

很多人认为方法不是游标,因为它没有说DECLARE CURSOR.我见过人们认为while循环比光标更快(我希望我已经消除了这个)或者使用FOR XML PATH执行组连接不执行隐藏的游标操作.在很多情况下看这个计划都会显示出真相.

在很多情况下,使用基于集合的游标更合适.但是有很多有效的用例,其中基于集合的等价物编写起来要复杂得多,优化器可以为两者或两者生成计划(例如,在循环表中更新统计信息的维护任务,为结果中的每个值调用存储过程,等等.对于许多大型多表查询也是如此,其中计划对于优化器来说太过怪异.在这些情况下,最好先将一些中间结果转储到临时结构中.对于游标的某些基于集合的等价物(如运行总计)也是如此.我还写过另一种方式,人们几乎总是本能地想到使用while循环/光标,并且有一些聪明的基于集合的替代方案要好得多.

更新2013-07-25

只是想添加一些额外的博客文章我已经写光标,你应该使用哪些选项,如果你有使用它们,并使用基于集合的查询,而不是环路,产生集:

运行总计的最佳方法 - 针对SQL Server 2012进行了更新

不同的光标选项有什么影响?

生成没有循环的集合或序列:[第1部分] [第2部分] [第3部分]


Pam*_*oud 6

SQL Server中游标的问题在于引擎是内部基于集合的,不像其他DBMS,如Oracle,它们是基于游标的内部.这意味着在SQL Server中创建游标时,需要创建临时存储,并且需要将基于集合的结果集复制到临时游标存储.您可以看到为什么这样做会非常昂贵,更不用说您可能在光标本身上执行的任何逐行处理.底线是基于集合的处理更有效,并且通常使用CTE或临时表可以更好地完成基于光标的操作.

话虽这么说,有些情况下光标可能是可以接受的,正如你所说的一次性操作.我能想到的最常见的用途是在维护计划中,您可能会迭代执行各种维护任务的服务器上的所有数据库.只要你限制你的使用并且不设计围绕RBAR(逐行 - 痛苦行)处理的整个应用程序,你应该没问题.