Oracle PL/SQL BULK COLLECT: FORALL の例

⚡ スマートサマリー

大量収集 Oracle PL/SQLは一度に多数の行をコレクションにフェッチし、FORALLは大量のDML操作をデータベースにプッシュバックします。どちらもSQLエンジンとPL/SQLエンジン間のコンテキストスイッチを削減し、パフォーマンスを向上させます。

  • 📦 一括収集: 複数の行を一度にコレクション変数に取得し、時間のかかる行ごとの取得処理を置き換えます。
  • 🔁 全ての人へ: 単一のコンテキストスイッチで、コレクション全体に対してINSERT、UPDATE、またはDELETE操作を1回実行します。
  • ☃ 制限条項: 各 BULK COLLECT フェッチがロードする行数を制限し、大きなテーブルでのセッション メモリを保護します。
  • 📊 一括収集属性: %BULK_ROWCOUNT(n)属性は、n番目のFORALL DMLステートメントによって影響を受けた行数を報告します。
  • ⚙️ 必要な収集物: INTO句は、ネストされたテーブルや連想配列などのコレクション型を対象とする必要があります。
  • 🤖 AI 支援: GitHub CopilotなどのAIアシスタントは、BULK COLLECTブロックとFORALLブロックを作成し、欠落しているLIMIT句を指摘します。

Oracle PL/SQLのBULK COLLECTとFORALL、LIMIT句の概要

一括収集とは何ですか?

一括収集により、コンテキストスイッチが削減されます。 SQL PL/SQLエンジンと連携し、SQLエンジンがレコードを一度に取得できるようにします。

Oracle PL / SQLの レコードを1つずつ取得するのではなく、まとめて取得する機能を提供します。この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がデータ全体をロードしようとすると、セッションメモリをより多く消費するためです。したがって、バルクコレクト操作のサイズは常に制限するのが良いでしょう。

このサイズ制限は、SELECT文にROWNUM条件を導入することで容易に実現できますが、カーソルの場合はこれは不可能です。

これを克服するために、 Oracle 一括処理に含めるレコード数を定義するLIMIT句が提供されています。

構文:

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

上記の構文では、カーソルフェッチステートメントは、LIMIT句とともにBULK COLLECTステートメントを使用しています。

一括収集属性

カーソル属性と同様に、BULK COLLECT には %BULK_ROWCOUNT(n) があり、これは FORALL ステートメントの n 番目の DML ステートメントで影響を受けた行数を返します。つまり、コレクション変数の各値に対して FORALL ステートメントで影響を受けたレコード数を返します。「n」は、行数が必要なコレクション内の値のシーケンスを示します。

例1: この例では、BULK COLLECT を使用して emp テーブルからすべての従業員名を抽出し、FORALL を使用してすべての従業員の給与を 5000 増やします。

以下のスクリーンショットは、この 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行目: ステートメント「SELECT emp_name FROM emp」に対してカーソルguru99_detを宣言します。
  • 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行目: コレクション lv_emp_name 内のすべてのレコードを出力するための FOR ループを設定します。
  • Code 12行目: FORALLを使用して、全従業員の給与を5000ずつ更新します。
  • Code 14行目: コミットする トランザクション.

よくあるご質問

いいえ。BULK COLLECT SELECT は NO_DATA_FOUND を発生させません。代わりに空のコレクションを返します。コレクションを取得する前に、必ず .COUNT メソッドでコレクションをテストしてください。pingそうしないと、0行の処理が黙って行われる可能性があります。

SAVE EXCEPTIONS を使用すると、個々の行が失敗した場合でも FORALL の実行を継続できます。失敗した行は SQL%BULK_EXCEPTIONS に格納され、その後 Oracle ORA-24381 を発生させ、それをトラップします 例外 各エラーを検査するハンドラ。

ループで多数の行を読み取る場合は、BULK COLLECT を使用してください。 カーソル FORループはスイッチごとに1行ずつ取得するため、バルクフェッチとFORALLを組み合わせることで、大規模な結果セットでも何倍も高速に実行できます。

BULK COLLECT は一度に多数の行を返すため、複数行コンテナが必要です。INTO ターゲットは コレクション 例えば、ネストされたテーブル、VARRAY、または連想配列などであり、単一のスカラー変数ではありません。

いいえ。FORALLヘッダーは、INSERT、UPDATE、DELETE、またはMERGEを1つだけ実行します。イテレーションごとに変更できるのは、VALUES句とWHERE句の値のみです。複数のステートメントを実行する場合は、個別のFORALLステートメントを使用してください。

バルク処理は、行単位のコードよりも数倍から100倍以上高速になる場合があります。これは、BULK COLLECTとFORALLによって、数千回に及ぶエンジンコンテキストの切り替えが数回に集約され、大量のデータに対するオーバーヘッドが大幅に削減されるためです。

Yes. GitHubコパイロット コメントから BULK COLLECT フェッチ、FORALL DML ループ、LIMIT 句のドラフトを作成し、コレクション型の宣言を提案しますが、バッチサイズとエラー処理についてはご自身で確認する必要があります。

AIアシスタントは、一度に1行ずつ取得または変更するループをスキャンし、BULK COLLECT、LIMIT、およびFORALLを使用して書き換えることを推奨します。この機械学習によるレビューにより、本番環境への移行前に、LIMIT制限の不足やパフォーマンスのボトルネックを検出できます。