Oracle PL/SQL BULK COLLECT: FORALL Приклад

⚡ Розумний підсумок

ОПТОВИЙ ЗБІР у Oracle PL/SQL вибирає багато рядків одночасно в колекцію, тоді як FORALL відправляє масу DML назад до бази даних. Обидва вирізані контексти перемикаються між механізмами SQL та PL/SQL, підвищуючи продуктивність.

  • 📦 ОПТОВИЙ ЗБІР: Вибирає кілька рядків за один прохід у змінну колекції, замінюючи повільну вибірку рядок за рядком.
  • 🔁 ДЛЯ ВСІХ: Виконує одну операцію INSERT, UPDATE або DELETE для всієї колекції за допомогою одного перемикача контексту.
  • 📏 Пункт LIMIT: Обмежує кількість рядків, які завантажує кожна вибірка BULK COLLECT, захищаючи пам'ять сеансу у великих таблицях.
  • 📊 Атрибути ОПТОВОГО ЗБОРУ: Атрибут %BULK_ROWCOUNT(n) повідомляє, на скільки рядків вплинув n-й оператор DML FORALL.
  • Необхідні колекції: Речення INTO має бути орієнтоване на тип колекції, такий як вкладена таблиця або асоціативний масив.
  • 🤖 Допомога AI: Помічники штучного інтелекту, такі як GitHub Copilot, створюють блоки BULK COLLECT та FORALL і позначають відсутній пункт LIMIT.

Oracle Огляд PL/SQL BULK COLLECT та FORALL з реченням LIMIT

Що таке BULK COLLECT?

ПАСОВЕ ЗБІРАННЯ зменшує перемикання контексту між SQL та движок PL/SQL і дозволяє движку SQL отримувати записи одночасно.

Oracle PL / SQL забезпечує функціональність масового отримання записів, а не по одному. Цей оператор BULK COLLECT можна використовувати в операторі SELECT для масового заповнення записів або для отримання курсор масово. Оскільки BULK COLLECT вибирає записи масово, речення INTO завжди повинно містити змінну типу колекції. Головною перевагою використання BULK COLLECT є підвищення продуктивності за рахунок зменшення взаємодії між базою даних та механізмом PL/SQL.

Синтаксис:

SELECT <column1> BULK COLLECT INTO bulk_variable FROM <table name>;
FETCH <cursor_name> BULK COLLECT INTO <bulk_variable>;

У наведеному вище синтаксисі BULK COLLECT використовується для збору даних з операторів SELECT та FETCH.

Речення FORALL

Оператор FORALL виконує Операції DML для даних масово. Це нагадує оператор циклу FOR, за винятком того, що в циклі FOR дії відбуваються на рівні запису, тоді як у FORALL немає концепції ЦИКЛУ. Натомість усі дані, присутні в заданому діапазоні, обробляються одночасно.

Синтаксис:

FORALL <loop_variable> in <lower range> .. <higher range>

<DML operations>;

У наведеному вище синтаксисі задана операція DML буде виконана для всіх даних, що знаходяться між нижнім та вищим діапазоном.

Речення LIMIT

Концепція масового збору завантажує всі дані в цільову змінну колекції як масове навантаження, тобто всі дані будуть заповнені в змінну колекції за один раз. Але це не рекомендується, коли загальна кількість записів, які потрібно завантажити, дуже велика, оскільки коли PL/SQL намагається завантажити всі дані, він споживає більше пам'яті сеансу. Отже, завжди добре обмежувати розмір цієї операції масового збору.

Цього обмеження розміру можна легко досягти, ввівши умову ROWNUM в оператор SELECT, тоді як у випадку курсора це неможливо.

Щоб подолати це, Oracle надав умову LIMIT, яка визначає кількість записів, які потрібно включити до масового оброблення.

Синтаксис:

FETCH <cursor_name> BULK COLLECT INTO <bulk_variable> LIMIT <size>;

У наведеному вище синтаксисі оператор вибірки курсора використовує оператор BULK COLLECT разом із реченням LIMIT.

Атрибути BULK COLLECT

Подібно до атрибутів курсора, BULK COLLECT має %BULK_ROWCOUNT(n), який повертає кількість рядків, на які впливає n-та DML-інструкція інструкції FORALL, тобто він видає кількість записів, на які впливає інструкція FORALL, для кожного окремого значення зі змінної колекції. Термін 'n' вказує на послідовність значень у колекції, для яких потрібна кількість рядків.

Приклад 1: У цьому прикладі ми проектуємо всі імена співробітників з таблиці emp за допомогою BULK COLLECT, а також збільшимо зарплату всіх співробітників на 5000 за допомогою FORALL.

На скріншоті нижче показано цей приклад BULK COLLECT та FORALL разом із його виводом у Oracle.

Приклад масового збору даних з LIMIT та FORALL для оновлення зарплати співробітника в Oracle PL / SQL

DECLARE
CURSOR guru99_det IS SELECT emp_name FROM emp;
TYPE lv_emp_name_tbl IS TABLE OF VARCHAR2(50);
lv_emp_name lv_emp_name_tbl;
BEGIN
OPEN guru99_det;
FETCH guru99_det BULK COLLECT INTO lv_emp_name LIMIT 5000;
FOR c_emp_name IN lv_emp_name.FIRST .. lv_emp_name.LAST
LOOP
Dbms_output.put_line('Employee Fetched:'||c_emp_name);
END LOOP;
FORALL i IN lv_emp_name.FIRST .. lv_emp_name.LAST
UPDATE emp SET salary=salary+5000 WHERE emp_name=lv_emp_name(i);
COMMIT;
Dbms_output.put_line('Salary Updated');
CLOSE guru99_det;
END;
/

Вихід

Employee Fetched:BBB
Employee Fetched:XXX
Employee Fetched:YYY
Salary Updated

Code Пояснення:

  • Code рядок 2: Оголошення курсора guru99_det для оператора 'SELECT emp_name FROM emp'.
  • Code рядок 3: Оголошення lv_emp_name_tbl як табличного типу VARCHAR2(50).
  • Code рядок 4: Оголошення lv_emp_name як типу lv_emp_name_tbl.
  • Code рядок 6: Відкриття курсору.
  • Code рядок 7: Отримання курсора за допомогою BULK COLLECT з розміром LIMIT, рівним 5000, у змінну lv_emp_name.
  • Code рядки 8-11: Налаштування циклу FOR для виведення всіх записів у колекції lv_emp_name.
  • Code рядок 12: Використання FORALL для оновлення зарплати всіх співробітників на 5000.
  • Code рядок 14: Здійснення угода.

Поширені запитання

Ні. BULK COLLECT SELECT ніколи не викликає NO_DATA_FOUND; натомість він повертає порожню колекцію. Завжди перевіряйте колекцію за допомогою методу .COUNT перед loo.ping, інакше ви можете мовчки обробити нуль рядків.

ЗБЕРЕЖЕННЯ ВИНЯТКІВ дозволяє FORALL продовжувати виконуватися, коли окремі рядки не вдаються. Рядки, що не вдалися, зберігаються в SQL%BULK_EXCEPTIONS, а потім Oracle викликає ORA-24381, який ви перехоплюєте в пастку виняток обробник для перевірки кожної помилки.

Використовуйте BULK COLLECT щоразу, коли цикл зчитує багато рядків. курсор Цикл FOR вибирає один рядок на комутатор, тому масова вибірка плюс FORALL може виконуватися в багато разів швидше на великих наборах результатів.

BULK COLLECT повертає багато рядків одночасно, тому потрібен багаторядковий контейнер. Ціль INTO має бути збір наприклад, вкладена таблиця, VARRAY або асоціативний масив, а не одна скалярна змінна.

Ні. Заголовок FORALL виконує лише одну операцію INSERT, UPDATE, DELETE або MERGE. За ітерацію можуть змінюватися лише значення в його реченнях VALUES та WHERE. Для кількох операторів використовуйте окремі оператори FORALL.

Масова обробка може бути в кілька разів, а то й понад сто разів швидшою, ніж рядковий код, оскільки BULK COLLECT та FORALL згортають тисячі перемикачів контексту движка в декілька, що значно скорочує накладні витрати на великі обсяги даних.

Так. Копілот GitHub створює вибірки BULK COLLECT, цикли DML FORALL та речення LIMIT з коментаря, а також пропонує оголошення типів колекцій, хоча вам слід самостійно переглянути розміри пакетів та обробку помилок.

Помічники штучного інтелекту сканують цикли, які вибирають або змінюють по одному рядку за раз, і рекомендують перезаписувати їх за допомогою BULK COLLECT, LIMIT та FORALL. Цей огляд машинного навчання виявляє пропущені обмеження LIMIT та вузькі місця продуктивності перед виробництвом.

Підсумуйте цей пост за допомогою: