概要
前回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文を組み合わせるのが最も早くできるのではないだろうか。引き続き様々な方向で検討していきたい。
最近のコメント