简体   繁体   English

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

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

I know that fetching a cursor will give me access to variables like %ROWCOUNT, %ROWTYPE, %FOUND, %NOTFOUND, %ISOPEN 我知道获取光标将允许我访问%ROWCOUNT,%ROWTYPE,%FOUND,%NOTFOUND,%ISOPEN等变量

...but I was wondering if there are any other reasons to use ...但我想知道是否还有其他原因可以使用

Open - Fetch - Close instructions to loop a cursor Open - Fetch - 关闭循环游标的指令

rather than 而不是

Loop the cursor with a FOR cycle... (In my opinion this is better becase it is simple) 用FOR循环循环光标......(在我看来这更好,因为它很简单)

What do you think? 你怎么看?

From a performance standpoint, the difference is a lot more complicated than the Tim Hall tip that OMG Ponies linked to would imply. 从性能的角度来看,差异比OMG Ponies所暗示的蒂姆霍尔提示要复杂得多。 I believe that this tip is an introduction to a larger section that has been excerpted for the web-- I expect that Tim went on to make most if not all of these points in the book. 我相信这个提示是对一个较大的部分的介绍,该部分已经被网络摘录 - 我希望Tim继续在书中创造大部分(如果不是全部的话)。 Additionally, this entire discussion depends on the Oracle version you're using. 此外,整个讨论取决于您使用的Oracle版本。 I believe this is correct for 10.2, 11.1, and 11.2 but there are definitely differences if you start going back to older releases. 我相信这对于10.2,11.1和11.2是正确的,但如果你开始回到旧版本,肯定存在差异。

The particular example in the tip, first of all, is rather unrealistic. 首先,提示中的特定示例是不切实际的。 I've never seen anyone code a single-row fetch using an explicit cursor rather than a SELECT INTO. 我从未见过有人使用显式游标而不是SELECT INTO编写单行提取代码。 So the fact that SELECT INTO is more efficient is of very limited practical importance. 因此,SELECT INTO更高效的事实具有非常有限的实际重要性。 If we're discussing loops, the performance we're interested in is how expensive it is to fetch many rows. 如果我们讨论循环,我们感兴趣的性能是获取许多行的成本是多少。 And that's where the complexity starts to come in. 这就是复杂性开始出现的地方。

Oracle introduced the ability to do a BULK COLLECT of data from a cursor into a PL/SQL collection in 10.1. Oracle引入了从游标到10.1中的PL / SQL集合进行BULK COLLECT数据收集的能力。 This is a much more efficient way to get data from the SQL engine to the PL/SQL collection because it allows you to minimize context shifts by fetching many rows at once. 这是一种将数据从SQL引擎传递到PL / SQL集合的更有效方法,因为它允许您通过一次获取多行来最小化上下文移位。 And subsequent operations on those collections are more efficient because your code can stay within the PL/SQL engine. 对这些集合的后续操作更有效,因为您的代码可以保留在PL / SQL引擎中。

In order to take maximum advantage of the BULK COLLECT syntax, though, you generally have to use explicit cursors because that way you can populate a PL/SQL collection and then subsequently use the FORALL syntax to write the data back to the database (on the reasonable assumption that if you are fetching a bunch of data in a cursor, there is a strong probability that you are doing some sort of manipulation and saving the manipulated data somewhere). 但是,为了最大限度地利用BULK COLLECT语法,您通常必须使用显式游标,因为这样您可以填充PL / SQL集合,然后使用FORALL语法将数据写回数据库(在合理的假设是,如果你在游标中获取一堆数据,很有可能你正在进行某种操作并在某处保存操纵数据)。 If you use an implicit cursor in a FOR loop, as OMG Ponies correctly points out, Oracle will be doing a BULK COLLECT behind the scenes to make the fetching of the data less expensive. 如果在FOR循环中使用隐式游标,正如OMG Ponies正确指出的那样,Oracle将在幕后进行BULK COLLECT以使得获取数据的成本更低。 But your code will be doing slower row-by-row inserts and updates because the data is not in a collection. 但是您的代码将逐行插入和更新,因为数据不在集合中。 Explicit cursors also offer the opportunity to set the LIMIT explicitly which can improve performance over the default of 100 for an implicit cursor in a FOR loop. 显式游标还提供了显式设置LIMIT的机会,这可以提高FOR循环中隐式游标的默认值100的性能。

In general, assuming that you're on 10.2 or greater and that your code is fetching data and writing it back to the database, 通常,假设您使用的是10.2或更高版本并且您的代码正在获取数据并将其写回数据库,

Fastest 最快的

  1. Explicit cursors doing a BULK COLLECT into a local collection (with an appropriate LIMIT) and using FORALL to write back to the database. 显式游标将BULK COLLECT执行到本地集合(具有适当的LIMIT)并使用FORALL写回数据库。
  2. Implicit cursors doing a BULK COLLECT for you behind the scenes along with single-row writes back to the datbase. 隐式游标在幕后为您执行BULK COLLECT以及单行写回数据库。
  3. Explicit cursors that are not doing a BULK COLLECT and not taking advantage of PL/SQL collections. 显式游标没有执行BULK COLLECT而没有利用PL / SQL集合。

Slowest 最慢

On the other hand, using implicit cursors gets you quite a bit of the benefit of using bulk operations for very little of the upfront cost in refactoring old code or learning the new feature. 另一方面,使用隐式游标可以在重构旧代码或学习新功能时,使用批量操作获得很少的前期成本。 If most of your PL/SQL development is done by developers whose primary language is something else or who don't necessarily keep up with new language features, FOR loops are going to be easier to understand and maintain than explicit cursor code that used all the new BULK COLLECT functionality. 如果您的大多数PL / SQL开发都是由主要语言不同或者不一定能跟上新语言特性的开发人员完成的,那么FOR循环将比使用所有语言的显式游标代码更容易理解和维护。新的BULK COLLECT功能。 And when Oracle introduces new optimizations in the future, it's far more likely that the implicit cursor code would get the benefit automatically while the explicit code may require some manual rework. 当Oracle在未来引入新的优化时,隐式游标代码更有可能自动获得好处,而显式代码可能需要一些手动返工。

Of course, by the time you're troubleshooting performance to the point where you really care about how much faster different variants of your looping code might be, you're often at the point where you would want to consider moving more logic into pure SQL and ditching the looping code entirely. 当然,当您对性能进行故障排除时,您真正关心循环代码的不同变体可能会有多快,您通常会考虑将更多逻辑转移到纯SQL中并完全抛弃循环代码。

The OPEN / FETCH / CLOSE is called explicit cursor syntax; OPEN / FETCH / CLOSE称为显式游标语法; the latter is called implicit cursor syntax. 后者称为隐式游标语法。

One key difference you've already noticed is that you can't use %FOUND/%NOTFOUND/etc in implicit cursors... Another thing to be aware of is that implicit cursors are faster than explicit ones--they read ahead (~100 records?) besides not supporting the explicit logic. 你已经注意到的一个关键区别是你不能在隐式游标中使用%FOUND /%NOTFOUND /等...另外需要注意的是隐式游标比显式游标更快 - 它们在前面读取(〜 100条记录?)除了不支持显式逻辑。

Additional info: 附加信息:

I don't know about any crucial differences in this two realizations besides one: for ... loop implicitly closes the cursor after the loop is finished and if open ... fetch ... close syntax you'd rather close the cursor yourself (just a good manner) - thought this is not a necessity: Oracle will close the cursor automatically outbound the visibility scope. 我不知道除了一个之外这两个实现中的任何关键差异: for ... loop在循环结束后隐式关闭光标,如果open ... fetch ... close语法你宁愿自己关闭光标(只是一种好的方式) - 认为这不是必需的:Oracle将自动关闭游标以查看可见范围。 Also you can't use %FOUND and %NOTFOUND in for ... loop cursors. 此外,您不能将%FOUND%NOTFOUND for ... loop游标。

As for me I find the for ... loop realization much easier to read and support. 至于我,我发现for ... loop实现更容易阅读和支持。

Correct me if I'm wrong but I think both have one nice feature what other one doesn't have. 如果我错了,请纠正我,但我认为两者都有一个很好的功能,其他人没有。

With for loop you can do like this: 使用for循环,你可以这样做:

for i in (select * from dual)
  dbms_output.put_line('ffffuuu');
end loop;

And with open .. fetch you can do like this: 使用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;

So with open fetch you can use dynamic cursors but with for loop you can define normal cursor without declaration. 因此,使用open fetch,您可以使用动态游标,但使用for循环,您可以定义普通游标而无需声明。

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

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