概要
前回READ TABLEのBINARY SEARCHを使用したパフォーマンス検証を行ってみたが、実用性に乏しいサンプルコードであった為、実際に使えそうなソースコードを用い、且つ、大量のデータで検証を実施した。
データはBKPF(約50万件)、BSEG(約110万件)を使用している。
サンプルコード:通常のLoop文
DATA: it_bkpf TYPE TABLE OF bkpf, wa_bkpf TYPE bkpf, it_bseg TYPE TABLE OF bseg, wa_bseg TYPE bseg. SELECT * INTO TABLE it_bkpf FROM bkpf. SELECT * INTO TABLE it_bseg FROM bseg. LOOP AT it_bkpf INTO wa_bkpf. LOOP AT it_bseg INTO wa_bseg WHERE bukrs = wa_bkpf-bukrs AND belnr = wa_bkpf-belnr AND gjahr = wa_bkpf-gjahr. ENDLOOP. ENDLOOP.
処理としては、単純にBKPFとBSEGを全件取得し、BKPFを元にBSEGを参照するというプログラムだ。WHERE句が内部的にどのような検索を行っているのは不明だが、おそらく110万件の検索を50万回行っていると想定している。プログラムはとてもシンプルであるが、60分以上プログラムが終了しないロジックとなってしまう。
次に上記をBINARY SEARCHを使い、且つ、最低限の検索回数となるよう変えてみよう。
サンプルコード:BINARY SEARCH + IF文
DATA: it_bkpf TYPE TABLE OF bkpf, wa_bkpf TYPE bkpf, it_bseg TYPE TABLE OF bseg, wa_bseg TYPE bseg, v_tabix TYPE sy-tabix. SELECT * INTO TABLE it_bkpf FROM bkpf. SELECT * INTO TABLE it_bseg FROM bseg. SORT it_bkpf BY bukrs belnr gjahr. SORT it_bseg BY bukrs belnr gjahr. LOOP AT it_bkpf INTO wa_bkpf. READ TABLE it_bseg TRANSPORTING NO FIELDS WITH KEY bukrs = wa_bkpf-bukrs belnr = wa_bkpf-belnr gjahr = wa_bkpf-gjahr BINARY SEARCH. v_tabix = sy-tabix. LOOP AT it_bseg INTO wa_bseg FROM v_tabix. IF wa_bseg-bukrs = wa_bkpf-bukrs AND wa_bseg-belnr = wa_bkpf-belnr AND wa_bseg-gjahr = wa_bkpf-gjahr. ELSE. EXIT. ENDIF. ENDLOOP. ENDLOOP.
赤字が最初のプログラムソースからの変更点となっている。
まず最初にBINARY SEARCHを使う上では必ずSORTをしておこう。テーブル上の主キーだけで検索している為、上記例ではおそらく問題ないと思うが、ショートダンプ発生の原因になりえるので、BINARY SEARCHとSORTは必ずセットで書く事をお勧めする。
次にREAD TABLEでBINARY SEARCHを行っているが、この段階で内部テーブルの値は必要ない為、TRANSPORTING NO FIELDSオプションを使い少しでもパフォーマンスを減らしている。
LOOPでは内部テーブルの検索開始位置をBINARY SEARCHを使って見つけた行のみを指定している。ポイントはWHERE句に条件を書かず、IF文でチェックしている点だ。
この例では50万件もの検索に2分もかからず検索できた。
最後にIF文で記述した条件をWHERE句にしたらどうなるのかという事を検証してみた。
サンプルコード:BINARY SEARCH + WHERE句
DATA: it_bkpf TYPE TABLE OF bkpf,
wa_bkpf TYPE bkpf,
it_bseg TYPE TABLE OF bseg,
wa_bseg TYPE bseg,
v_tabix TYPE sy-tabix.
SELECT * INTO TABLE it_bkpf FROM bkpf.
SELECT * INTO TABLE it_bseg FROM bseg.
SORT it_bkpf BY bukrs belnr gjahr.
SORT it_bseg BY bukrs belnr gjahr.
LOOP AT it_bkpf INTO wa_bkpf.
READ TABLE it_bseg TRANSPORTING NO FIELDS
WITH KEY bukrs = wa_bkpf-bukrs
belnr = wa_bkpf-belnr
gjahr = wa_bkpf-gjahr BINARY SEARCH.
v_tabix = sy-tabix.
LOOP AT it_bseg INTO wa_bseg FROM v_tabix
WHERE bukrs = wa_bkpf-bukrs
AND belnr = wa_bkpf-belnr
AND gjahr = wa_bkpf-gjahr.
ENDLOOP.
ENDLOOP.
実行結果
対象ケース | 実行結果(分) |
通常のLoop文 | 2650分 |
BINARY SEARCH + IF文 | 2分 |
BINARY SEARCH + WHERE句 | 1470分 |
上記のように、想像以上の差異が発生した。
通常のLOOP文は想定通りであるが、WHERE句で指定した場合もパフォーマンスとしてはそれほど良くなかった。おそらく、インデックスの指定によって、検索対照は徐々に減っていくが、初期の検索がボトルネックになっているのだろう。
例えば、BPKFの1件目ではBSEGは150万回検索されている。BKPFの40万件目ではBSEGは30万回検索されるという風になっているのであろう。FROMだけ指定したとしてもWHERE句で条件をするだけではそれほど意味がない事が理解できる。IF文で指定した場合はBKPF1件に対してBSEGの検索はたった3回しかされない事になる。その為、これほどのパフォーマンスの差が発生したのだろう。
※BKPF1件に対して、BSEG3件という前提で記述しました。
パフォーマンスの検証としては2度程(内部テーブルのパフォーマンス向上:BINARY SEARCH有り無しの違い、LOOP文の高速化(失敗))記事に掲載したが、BINARY SEARCHと IF文を組み合わせるのが最も早くできるのではないだろうか。引き続き様々な方向で検討していきたい。
最近のコメント