プログラム研究所
ソフトウェア開発やプログラミングの豆知識を載せています。
04 | 2018/05 | 06
S M T W T F S
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -

スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

SELECTのBULK化による高速化
PL/SQLにテーブルから大量データを読込み、ループ処理で計算や加工をおこなうようなルーチンを作るとき、カーソルからのデータの読み込みをBULK化すると高速に処理出来ます。高速化できるのはSQLエンジンとPL/SQLエンジンのコンテキストスイッチを極小化するためです。入力テーブルに関し下記のようなルーチンを適当なスコープに作成して活用することができます。

内部のデータ構造

{source}の部分は入力元のテーブル名に置換してください。

/* 入力テーブルを読み込むカーソルを定義 */ cursor curSource is SELECT SRC.col1, SRC.col2, ... FROM {SourceTable} AS SRC WHERE .......... ORDER BY .....; type tab{source} is table of curSource%rowtype index by pls_integer; bulk_buf tab{source}; bulk_idx pls_integer; bulk_siz constant pls_integer := 500; /* バッファ既定サイズ;最適値はテストで決まる */

内部バッファのサイズ bulk_siz の最適値は実行環境で速度を実測した上で決めてください。一般にサイズが小さいうちはリニアに速度が向上しますが、ある大きさ以上になると頭打ちになります。

プロシージャ定義

{source}の部分は出力先のテーブル名に置換してください。

err_buf{source} exception; --カーソルはアプリケーションに公開 cursor curSource; procedure open{source} is begin --カーソルをオープン open curSource; --バッファを空にする bulk_buf.delete; --次の読み出し位置 bulk_idx := 0; exception when others then if curSource%isopen then close curSource; end if; raise err_buf{source}; end open{source}; procedure close{source} is begin --バッファを空にする bulk_buf.delete; bulk_idx := 0; --カーソルをクローズ if curSource%isopen then close curSource; end if; exception when others then if curSource%isopen then close curSource; end if; raise err_buf{source}; end close{source}; function fetch{source}(out_buf out nocopy curSource%rowtype) return boolean is isValid boolean; begin -- 次の読み出し位置がバッファサイズを超えてない場合はデータ有効 if bulk_idx <= bulk_buf.count then isValid := true; -- 次の読み出し位置がバッファサイズを超えている場合はデータ無効。次のブロックの読み出しを試みる else bulk_buf.delete; bulk_idx := 0; fetch curSource bulk collect into bulk_buf limit bulk_siz; if bulk_buf.count = 0 then isValid := false; else isValid := true; bulk_idx := 1; end if; end if; -- データが有効な場合はデータを返却する if isValid then out_buf := bulk_buf(bulk_idx); bulk_idx := bulk_idx + 1; -- バッファが有効でない場合はもうデータがない else out_buf := null; end if; return isValid; exception when others then if curSource%isopen then close curSource; end if; raise err_buf{source}; end fetch{source};

サンプル

{source}の部分は出力先のテーブル名に置換してください。

アプリケーションでは1レコードずつ転送しているようにコーディングしますが、実際は、openでカーソルとバッファを準備し、fetch内部でバッファリングして1レコードずつ戻します。最後にアプリケーションは内部バッファをクリアしカーソルをクローズするためにcloseを呼びます。

declare rec curSource%rowtype; begin /* 前処理 */ open{source}; /* ソースデータの読み込みループ */ loop rec := null; exit when fetch{source} (rec); /* 行ごとの処理 */ ANY_PROC ( rec ); : end loop; /* 後処理 */ close{source} /* 例外処理 */ exception when err_buf{source} then dbms_output.put_line('処理失敗...'); end;
スポンサーサイト

コメント
リッチなマダムとバームクーヘン
I29eg48c
リッチなマダムとバームクーヘン
美味しいよ!
http://w0t5f8qX.sekkusu.info/w0t5f8qX/
[2013/02/02 16:46] URL | 三杯 #p7SAMsGM [ 編集 ]


コメントの投稿














管理者にだけ表示を許可する


トラックバック
トラックバック URL
http://proglabo.blog.fc2.com/tb.php/8-8a860609
この記事にトラックバックする(FC2ブログユーザー)

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。