Навіщо використовувати явні курсори замість звичайних циклів?


12

Я писав основні веб-додатки протягом року (для db Oracle), і оскільки функції досить прості, більшість з нас дотримуються звичайних ЗА циклів, щоб отримати наші дані:

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

Але, здається, курсори - це «правильний» спосіб робити справи. Я можу знайти багато інформації про те, що таке курсори, і різні способи прокрутити їх, але я не можу знайти вагому причину, чому їх використовувати для звичайних циклів FOR. Чи це залежить від потреб процедури? Чи є притаманні мені переваги, про які слід знати?


Цей тип FOR- лише інший спосіб використання курсорів. Дивіться документи: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… Як би там не було, що робить htp.prn ()?
dezso

Це одна з наших вихідних функцій. Отже, чи маєте ви перевагу, який метод використовувати?
ini

Для цього типу речей FORцикл набагато легше читається. Я схильний використовувати «справжні» курсори лише в тому випадку, якщо мені доведеться відступити назад, а не лише вперед. Я задав це інше питання, тому що я можу уявити функцію таблиці замість htp.prn().
dezso

Варто зазначити, що обидві форми курсору мають нижчу продуктивність у порівнянні з чистим рішенням SQL - особливо це стосується операторів DML.
Девід Олдрідж

Відповіді:


7

Курсор може бути явним або неявним, і будь-який тип може бути використаний у циклі FOR. У вашому питанні дійсно два аспекти.

  1. Навіщо використовувати явний курсор циклу FOR над неявним курсором циклу FOR?

    • Використовуйте явний цикл курсора FOR, коли запит буде повторно використаний, інакше кращий неявний курсор.
  2. Навіщо використовувати цикл FETCH, а не цикл FOR, який не має явного FETCH?

    • Використовуйте FETCH всередині циклу, коли вам потрібно зібрати велику кількість або коли вам потрібен динамічний SQL.

Ось корисна інформація з документації.

Приклад неявного курсору для LOOP

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Приклад явного курсору для LOOP

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Неявний курсор

Неявний курсор - це сеансовий курсор, який будується та керується PL / SQL. PL / SQL відкриває неявний курсор кожного разу при запуску оператора SELECT або DML. Ви не можете керувати неявним курсором, але ви можете отримати інформацію з його атрибутів.

Неявний курсор закривається після запуску відповідного оператора; однак, значення його атрибутів залишаються доступними до запуску іншого оператора SELECT або DML.

Неявні атрибути курсора: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

Явний курсор

Явний курсор - це курсор сеансу, який ви створюєте та керуєте. Ви повинні оголосити та визначити явний курсор, давши йому ім’я та пов'язуючи його із запитом (як правило, запит повертає кілька рядків). Потім ви можете обробити набір запитів будь-яким із цих способів:

Відкрийте явний курсор (з оператором OPEN), витягуйте рядки з набору результатів (із твердженням FETCH) та закрийте явний курсор (з оператором CLOSE).

Використовуйте явний курсор у курсорі для оператора LOOP (див. "Обробка результатів запиту обробка курсором для заяв LOOP").

Ви не можете призначити значення явному курсору, використовувати його в виразі або використовувати його як формальний параметр підпрограми або змінна хост. Ви можете робити ці речі зі змінною курсору (див. "Змінні курсори").

На відміну від неявного курсору, ви можете посилатися на явний курсор або змінну курсора за його назвою. Тому явний курсор або змінна курсору називається названим курсором.

Курсор для заяв про LOOP

Курсор для оператора LOOP дозволяє запустити оператор SELECT, а потім негайно провести цикл через рядки набору результатів. Це твердження може використовувати або неявний, або явний курсор.


1
Неявні курсори отримують одночасно 100 рядків, починаючи з 10 г.
Девід Олдрідж

16

В опублікованому вами коді використовується курсор. Він використовує неявну петлю курсору.

Є випадки, коли використання явного циклу курсора (тобто оголошення змінної CURSOR в розділі декларації) створює чистіший код або кращу ефективність

  1. Якщо у вас є складніші запити, які ви не можете переробити на перегляд, це може полегшити читання коду, якщо ваш цикл повторюється student_cursorзамість того, щоб включати 30-рядовий оператор SQL, який вкладає купу логіки. Наприклад, якщо ви роздруковували всіх студентів, які отримали дозвіл на здобуття випускних курсів, і які включали приєднання до таблиць, які мали свої академічні записи, вимоги програми їх ступеня, таблиці з інформацією про навчальні запаси, таблиці з інформацією про прострочені бібліотечні книги, таблиці з інформацією про неоплачені збори, адміністративні зміни та ін., можливо, має сенс переробити код, щоб цей запит не застряг посередині коду, який стосується подання списку користувачеві. Це може включати створення представлення, яке б уклало всю цю логіку. Або це може включати створення явного курсору, який був оголошений або як частина поточного блоку PL / SQL, або як якийсь блок PL / SQL вищого рівня (тобто курсор, оголошений у пакеті), щоб він був багаторазовим. Або це може включати щось інше для інкапсуляції та повторного використання (скажімо, натомість створення функції конвеєрної таблиці).
  2. Якщо ви хочете використовувати масові операції в PL / SQL, ви, як правило, хочете використовувати явні курсори. Ось нитка StackOverflow, яка обговорює відмінності у виконанні між явними та неявними курсорами . Якщо все, що ви робите, дзвонить htp.prn, то, BULK COLLECTймовірно, нічого вам не купує. В інших випадках, однак, це може призвести до значних поліпшень продуктивності.

2

Я бачу, що багато розробників використовують явні курсори замість неявних курсорів зі старої звички. Це тому, що ще у версії Oracle 7 це було завжди більш ефективним шляхом. Сьогодні взагалі навпаки. Спеціально з оптимізатором, який за потреби може переписати неявний курсор для циклів для масового збору.


0

Нещодавно мені довелося переписати купу запитів із неявного циклу FOR в явні курсори. Причина полягала в тому, що запити отримували дані із зовнішньої бази даних за посиланням, і ця база даних мала інше кодування, ніж наша локальна база даних. При передачі даних з неявного курсору в локально визначений тип запису траплялися таємничі переривчасті помилки (лише в певних конкретних рядках). Наша DBA нам це пояснила, ми самі не змогли б дійти до цього. Схоже, це помилка в Oracle, про яку повідомлялося.

Нам рекомендували переписати все, використовуючи явні курсори, і помилка зникла.

Не головна причина, яку ви можете використовувати явної над неявною, але варто зазначити.

EDIT: Oracle 12c.


Чи можете ви додати номер помилки та / або нотатки, щоб ті, хто читає це, могли дізнатися більше про симптоми та якщо / коли це вирішено?
Лі Ріффер

На жаль, повідомлення про помилки було зроблено одним із наших DBA, я не маю доступу до цієї інформації.
Роботрон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.