我知道获取光标会让我访问%ROWCOUNT,%ROWTYPE,%FOUND,%NOTFOUND,%ISOPEN
等变量...但我想知道是否还有其他理由可以使用
打开 - 获取 - 关闭循环游标的说明
而不是
使用FOR循环循环光标...(在我看来这更好,因为它很简单)
您怎么看?
答案 0 :(得分:27)
从表现的角度来看,差异比Tim Hall tip that OMG Ponies linked to所暗示的要复杂得多。我相信这个提示是对一个较大的部分的介绍,该部分已经被网络摘录 - 我希望Tim继续在书中创造大部分(如果不是全部的话)。此外,整个讨论取决于您使用的Oracle版本。我相信这对于10.2,11.1和11.2是正确的,但如果你开始回到旧版本,肯定存在差异。
首先,提示中的特定示例是不切实际的。我从未见过有人使用显式游标而不是SELECT INTO编写单行提取代码。因此,SELECT INTO更高效的事实具有非常有限的实际重要性。如果我们讨论循环,我们感兴趣的性能是获取许多行的成本是多少。这就是复杂性开始出现的地方。
Oracle引入了从游标到10.1中的PL / SQL集合中执行数据BULK COLLECT的功能。这是一种将数据从SQL引擎传递到PL / SQL集合的更有效方法,因为它允许您通过一次获取多行来最小化上下文移位。对这些集合的后续操作更有效,因为您的代码可以保留在PL / SQL引擎中。
为了最大限度地利用BULK COLLECT语法,您通常必须使用显式游标,因为这样您可以填充PL / SQL集合,然后使用FORALL语法将数据写回数据库(在合理的假设下,如果你在游标中获取一堆数据,很可能你正在进行某种操作并在某处保存操纵数据)。如果在FOR循环中使用隐式游标,正如OMG Ponies正确指出的那样,Oracle将在幕后进行BULK COLLECT以使得获取数据的成本更低。但是您的代码将逐行插入和更新,因为数据不在集合中。显式游标还提供了显式设置LIMIT的机会,这可以提高FOR循环中隐式游标的默认值100的性能。
一般情况下,假设您使用的是10.2或更高版本并且您的代码正在获取数据并将其写回数据库,
<强>最快强>
<强>最慢强>
另一方面,使用隐式游标可以在重构旧代码或学习新功能时,使用批量操作获得很少的前期成本。如果您的大多数PL / SQL开发都是由主要语言不同或者不一定能跟上新语言特性的开发人员完成的,那么FOR循环将比使用所有语言的显式游标代码更容易理解和维护。新的BULK COLLECT功能。当Oracle在未来引入新的优化时,隐式游标代码更有可能自动获得好处,而显式代码可能需要一些手动返工。
当然,当您对性能进行故障排除时,您真正关心循环代码的不同变体可能会更快,您通常需要考虑移动更多逻辑进入纯SQL并完全抛弃循环代码。
答案 1 :(得分:7)
OPEN / FETCH / CLOSE称为显式游标语法;后者称为隐式游标语法。
你已经注意到的一个关键区别是你不能在隐式游标中使用%FOUND /%NOTFOUND / ...另外需要注意的是隐式游标比显式游标更快 - 它们读取提前(约100条记录?)除了不支持显式逻辑。
其他信息:
答案 2 :(得分:3)
除了一个之外,我不知道这两个实现中的任何关键差异:for ... loop
在循环结束后隐式关闭游标,如果open ... fetch ... close
语法你宁愿自己关闭游标( (只是一种好的方式) - 认为这不是必需的:Oracle会自动关闭游标以查看可见范围。另外,您无法在%FOUND
游标中使用%NOTFOUND
和for ... loop
。
至于我,我发现for ... loop
实现更容易阅读和支持。
答案 3 :(得分:3)
如果我错了,请纠正我,但我认为两者都有一个很好的功能,而另一个则没有。
使用for循环,你可以这样做:
for i in (select * from dual)
dbms_output.put_line('ffffuuu');
end loop;
使用open .. fetch你可以这样做:
declare
cur sys_refcursor;
tmp dual.dummy%type;
begin
open cur for 'select dummy from dual';
loop
fetch cur into tmp;
exit when cur%notfound;
dbms_output.put_line('ffffuuu');
end loop;
close cur;
end;
因此,使用open fetch可以使用动态游标,但是使用for循环可以定义普通游标而无需声明。