Разница между FETCH/FOR для петли CURSOR в PL/SQL

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

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

Open - Fetch - Закрыть инструкции для циклического перемещения курсора

а не

Настройте курсор на цикл FOR... (По-моему, это лучше, потому что это просто)

Как вы думаете?

Ответ 1

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

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

Oracle представила возможность делать BULK COLLECT данных из курсора в коллекцию 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 или больше и что ваш код извлекает данные и записывает их обратно в базу данных,

Быстрый

  • Явные курсоры, выполняющие BULK COLLECT в локальной коллекции (с соответствующим LIMIT) и используя FORALL для записи в базу данных.
  • Неявные курсоры, выполняющие BULK COLLECT для вас за кулисами вместе с однострочной записью обратно в базу данных.
  • Явные курсоры, которые не выполняют BULK COLLECT и не используют коллекции PL/SQL.

Slowest

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

С помощью цикла 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;

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