繁体   English   中英

FETCH / FOR之间的区别是在PL / SQL中循环CURSOR

[英]Difference between FETCH/FOR to loop a CURSOR in PL/SQL

我知道获取光标将允许我访问%ROWCOUNT,%ROWTYPE,%FOUND,%NOTFOUND,%ISOPEN等变量

...但我想知道是否还有其他原因可以使用

Open - Fetch - 关闭循环游标的指令

而不是

用FOR循环循环光标......(在我看来这更好,因为它很简单)

你怎么看?

从性能的角度来看,差异比OMG Ponies所暗示的蒂姆霍尔提示要复杂得多。 我相信这个提示是对一个较大的部分的介绍,该部分已经被网络摘录 - 我希望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或更高版本并且您的代码正在获取数据并将其写回数据库,

最快的

  1. 显式游标将BULK COLLECT执行到本地集合(具有适当的LIMIT)并使用FORALL写回数据库。
  2. 隐式游标在幕后为您执行BULK COLLECT以及单行写回数据库。
  3. 显式游标没有执行BULK COLLECT而没有利用PL / SQL集合。

最慢

另一方面,使用隐式游标可以在重构旧代码或学习新功能时,使用批量操作获得很少的前期成本。 如果您的大多数PL / SQL开发都是由主要语言不同或者不一定能跟上新语言特性的开发人员完成的,那么FOR循环将比使用所有语言的显式游标代码更容易理解和维护。新的BULK COLLECT功能。 当Oracle在未来引入新的优化时,隐式游标代码更有可能自动获得好处,而显式代码可能需要一些手动返工。

当然,当您对性能进行故障排除时,您真正关心循环代码的不同变体可能会有多快,您通常会考虑将更多逻辑转移到纯SQL中并完全抛弃循环代码。

OPEN / FETCH / CLOSE称为显式游标语法; 后者称为隐式游标语法。

你已经注意到的一个关键区别是你不能在隐式游标中使用%FOUND /%NOTFOUND /等...另外需要注意的是隐式游标比显式游标更快 - 它们在前面读取(〜 100条记录?)除了不支持显式逻辑。

附加信息:

我不知道除了一个之外这两个实现中的任何关键差异: for ... loop在循环结束后隐式关闭光标,如果open ... fetch ... close语法你宁愿自己关闭光标(只是一种好的方式) - 认为这不是必需的:Oracle将自动关闭游标以查看可见范围。 此外,您不能将%FOUND%NOTFOUND for ... loop游标。

至于我,我发现for ... loop实现更容易阅读和支持。

如果我错了,请纠正我,但我认为两者都有一个很好的功能,其他人没有。

使用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循环,您可以定义普通游标而无需声明。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM