Разница между FETCH / FOR для цикла CURSOR в PL / SQL - PullRequest
14 голосов
/ 08 октября 2010

Я знаю, что выбор курсора даст мне доступ к таким переменным, как% ROWCOUNT,% ROWTYPE,% FOUND,% NOTFOUND,% ISOPEN

... но мне было интересно, есть ли другие причины использовать

Открыть - Извлечь - Закрыть инструкции для зацикливания курсора

вместо

Цикл курсора с циклом FOR ... (На мой взгляд, это лучше, потому что это просто)

Что ты думаешь?

Ответы [ 4 ]

27 голосов
/ 08 октября 2010

С точки зрения производительности, разница намного сложнее, чем совет Tim Hall, который OMG Ponies связывает с . Я полагаю, что этот совет является введением в более крупный раздел, который был извлечен для сети - я ожидаю, что Тим продолжил делать большинство, если не все из этих пунктов в книге. Кроме того, все это обсуждение зависит от используемой вами версии Oracle. Я считаю, что это правильно для 10.2, 11.1 и 11.2, но есть определенные различия, если вы начнете возвращаться к более старым версиям.

Конкретный пример в подсказке, прежде всего, довольно нереалистичен. Я никогда не видел, чтобы кто-то кодировал однорядную выборку, используя явный курсор, а не SELECT INTO. Поэтому тот факт, что SELECT INTO более эффективен, имеет очень ограниченное практическое значение. Если мы обсуждаем циклы, то производительность, которая нас интересует, заключается в том, насколько дорого обходится получение множества строк. И вот тут начинается сложность.

Oracle представила возможность СОБЫТИЯ ОБЪЕМА ДАННЫХ из курсора в коллекцию PL / SQL в 10.1. Это гораздо более эффективный способ передачи данных из механизма SQL в коллекцию PL / SQL, поскольку он позволяет минимизировать сдвиги контекста, выбирая сразу несколько строк. И последующие операции с этими коллекциями более эффективны, потому что ваш код может оставаться в движке PL / SQL.

Чтобы максимально использовать синтаксис BULK COLLECT, вам, как правило, приходится использовать явные курсоры, потому что таким образом вы можете заполнить коллекцию PL / SQL, а затем использовать синтаксис FORALL для записи данных обратно в базу данных. (исходя из разумного предположения, что если вы выбираете кучу данных в курсоре, существует высокая вероятность того, что вы выполняете какие-то манипуляции и сохраняете манипулированные данные где-то). Если вы используете неявный курсор в цикле FOR, как правильно указывает OMG Ponies, Oracle выполнит BULK COLLECT за кулисами, чтобы сделать выборку данных менее дорогой. Но ваш код будет выполнять медленные построчные вставки и обновления, потому что данные не находятся в коллекции. Явные курсоры также предоставляют возможность явной установки LIMIT, что может повысить производительность по сравнению со значением по умолчанию 100 для неявного курсора в цикле FOR.

В общем, если вы используете версию 10.2 или выше и ваш код выбирает данные и записывает их обратно в базу данных,

быстрый

  1. Явные курсоры делают BULK COLLECT в локальную коллекцию (с соответствующим LIMIT) и используют FORALL для обратной записи в базу данных.
  2. Неявные курсоры выполняют БОЛЬШУЮ КОЛЛЕКЦИЮ для вас за кулисами вместе с однорядной записью обратно в базу данных.
  3. Явные курсоры, которые не выполняют BULK COLLECT и не используют преимущества коллекций PL / SQL.

Slowest

С другой стороны, использование неявных курсоров дает вам немало преимуществ от использования массовых операций за очень небольшие первоначальные затраты при рефакторинге старого кода или изучении новой функции. Если большая часть вашей разработки на PL / SQL выполняется разработчиками, основной язык которых является чем-то другим или которые не обязательно идут в ногу с новыми языковыми возможностями, циклы FOR будут легче понять и поддерживать, чем явный код курсора, который использовал все новая функциональность BULK COLLECT. И когда Oracle вводит новые оптимизации в будущем, гораздо более вероятно, что неявный код курсора получит выгоду автоматически, в то время как явный код может потребовать некоторой ручной доработки.

Конечно, к тому моменту, когда вы устраняете неполадки с производительностью до того момента, когда вы действительно заботитесь о том, насколько быстрыми могут быть различные варианты вашего зацикливающегося кода, вы часто приходите к тому, что вам захочется подумать о перемещении большей логики в чистый SQL и полностью исключая зацикливание кода.

7 голосов
/ 08 октября 2010

OPEN / FETCH / CLOSE называется явным синтаксисом курсора;последний называется неявным синтаксисом курсора.

Одно ключевое отличие, которое вы уже заметили, состоит в том, что вы не можете использовать% FOUND /% NOTFOUND / etc в неявных курсорах ... Еще одна вещь, о которой следует помнить, это то, что неявные курсоры быстрее, чем явныеОни читают вперед (~ 100 записей?), кроме того, что не поддерживают явную логику.

Дополнительная информация:

3 голосов
/ 08 октября 2010

Поправь меня, если я ошибаюсь, но я думаю, что у обоих есть одна приятная особенность, которой нет у другой.

С помощью цикла for вы можете сделать так:

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

А с открытым .. 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;

Так что с открытой выборкой вы можете использовать динамические курсоры, но с помощью цикла for вы можете определить нормальный курсор без объявления.

3 голосов
/ 08 октября 2010

Я не знаю ни о каких принципиальных различиях в этих двух реализациях, кроме одной: for ... loop неявно закрывает курсор после завершения цикла, и если синтаксис open ... fetch ... close, вы бы предпочли закрыть курсор самостоятельно (просто хороший способ ) - думал, что в этом нет необходимости: Oracle автоматически закроет курсор, выходящий из области видимости. Также нельзя использовать %FOUND и %NOTFOUND в for ... loop курсорах.

Что касается меня, я считаю, что for ... loop реализация намного проще для чтения и поддержки.

...