我可以理解为了避免因为开销和不便而不得不使用光标,但看起来有一些严重的光标 - 恐惧症 - 狂热正在进行,人们将不遗余力地避免使用光标.
例如,有一个问题询问如何使用游标执行明显无关紧要的操作,并使用带有递归自定义函数的公用表表达式(CTE)递归查询提出接受的答案,即使这会将可处理的行数限制为32 (由于sql server中的递归函数调用限制).这让我觉得它是系统寿命的可怕解决方案,更不用说为了避免使用简单的光标而付出的巨大努力.
这种疯狂仇恨的原因是什么?有一些"着名的权威"发布了针对游标的法特瓦吗?一些无法形容的邪恶是否潜伏在游戏的核心,腐蚀了儿童的道德或什么?
维基问题,答案比代表更感兴趣.
相关信息:
SQL Server快进游标
编辑:让我更精确:我理解不应该使用游标而不是正常的关系操作 ; 这是一个明智的选择.我不明白的是,即使游标是一种更简单和/或更有效的解决方案,人们也会不顾一切地避开光标,就像他们有傻瓜一样.困扰我的是非理性的仇恨,而不是明显的技术效率.
游标的"开销"仅仅是API的一部分.游标是RDBMS的部分工作方式.经常CREATE TABLE
并且INSERT
有SELECT
语句,而实现是明显的内部游标实现.
使用更高级别的"基于集合的运算符"捆绑将游标结果集合到单个结果集中,这意味着更少的API来回传递.
游标早于提供一流集合的现代语言.旧C,COBOL,Fortran等不得不一次处理一行,因为没有可以广泛使用的"集合"概念.Java,C#,Python等具有包含结果集的一流列表结构.
缓慢的问题
在某些圈子中,关系连接是一个谜,人们会编写嵌套游标而不是简单连接.我已经看到了真正的史诗嵌套循环操作,它被写成了很多很多游标.击败RDBMS优化.而且跑得很慢.
简单的SQL重写以使用连接替换嵌套的游标循环,并且单个平面游标循环可以使程序在第100次运行.[他们以为我是优化之神.我所做的只是用连接替换嵌套循环.仍然使用游标.]
这种混淆常常导致对游标的起诉.但是,它不是光标,而是光标的误用就是问题.
尺寸问题
对于真正的史诗结果集(即将表转储到文件中),游标是必不可少的.基于集合的操作无法将非常大的结果集实现为内存中的单个集合.
备择方案
我尝试尽可能多地使用ORM层.但这有两个目的.首先,游标由ORM组件管理.其次,SQL与应用程序分离为配置文件.并不是游标很糟糕.编码所有打开,关闭和提取的编码不是增值编程.
游标使人们过度地将程序思维模式应用于基于集合的环境.
他们很慢!
来自SQLTeam:
请注意,游标是访问SQL Server内部数据的最慢方式.只应在真正需要一次访问一行时使用.我能想到的唯一原因是在每一行调用存储过程.在Cursor Performance文章中,我发现游标比基于set的替代方案慢30多倍.
上面有一个答案说"游标是访问SQL Server内部数据的最慢方式...游标比基于集合的替代方案慢30多倍."
在许多情况下,这种说法可能是正确的,但作为一揽子声明,这是有问题的.例如,在我想要执行更新或删除操作的情况下,我已经很好地利用了游标,这些操作会影响接收常量生产读取的大型表的许多行.运行一次执行这些更新的存储过程最终比基于集合的操作更快,因为基于集合的操作与读取操作冲突并最终导致可怕的锁定问题(并且可能完全终止生产系统,在极端的情况下).
在没有其他数据库活动的情况下,基于集合的操作普遍更快.在生产系统中,它取决于.
游标倾向于在基于集合的操作更好的地方开始使用SQL开发人员.特别是当人们在学习传统编程语言后学习SQL时,"迭代这些记录"的心态往往会导致人们不恰当地使用游标.
最严重的SQL书籍包括一章禁止使用游标; 精心编写的文章清楚地表明游标有它们的位置,但不应该用于基于集合的操作.
很明显,游标是正确的选择,或者至少是正确的选择.
当使用游标方法时,优化器通常不能使用关系代数来转换问题.通常游标是解决问题的好方法,但SQL是一种声明性语言,数据库中有很多信息,从约束到统计和索引,这意味着优化器有很多选项可以解决问题,而游标几乎明确指示解决方案.
在Oracle PL/SQL游标中,不会导致表锁,并且可以使用批量收集/批量提取.
在Oracle 10中经常使用的隐式游标
for x in (select ....) loop --do something end loop;
一次隐式提取100行.显式批量收集/批量获取也是可能的.
但是PL/SQL游标是最后的手段,当您无法解决基于集合的SQL的问题时,请使用它们.
另一个原因是并行化,数据库比逐行命令式代码更容易并行化基于大型集的语句.这也是函数式编程变得越来越流行的原因(Haskell,F#,Lisp,C#LINQ,MapReduce ......),函数式编程使并行化变得更容易.每台计算机的CPU数量正在增加,因此并行化变得越来越成问题.
通常,因为在关系数据库中,使用游标的代码性能比基于集合的操作差一个数量级.
上面的答案并未充分强调锁定的重要性.我不是游标的忠实粉丝,因为它们经常导致表级锁定.