概要
前回READ TABLEのBINARY SEARCHを使用したパフォーマンス検証を行ってみたが、実用性に乏しいサンプルコードであった為、実際に使えそうなソースコードを用い、且つ、大量のデータで検証を実施した。
データはBKPF(約50万件)、BSEG(約110万件)を使用している。
サンプルコード:通常のLoop文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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文
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 |
DATA: it_bkpf TYPE TABLE OF bkpf, wa_bkpf TYPE bkpf, it_bseg TYPE TABLE OF bseg, wa_bseg TYPE bseg, <span style="color:#cf2e2e" class="tadv-color">v_tabix TYPE sy-tabix.</span> SELECT * INTO TABLE it_bkpf FROM bkpf. SELECT * INTO TABLE it_bseg FROM bseg. <span style="color:#cf2e2e" class="tadv-color">SORT it_bkpf BY bukrs belnr gjahr. SORT it_bseg BY bukrs belnr gjahr.</span> LOOP AT it_bkpf INTO wa_bkpf. <span style="color:#cf2e2e" class="tadv-color"> 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.</span> LOOP AT it_bseg INTO wa_bseg <span style="color:#cf2e2e" class="tadv-color">FROM v_tabix.</span> <span style="color:#cf2e2e" class="tadv-color"> IF wa_bseg-bukrs = wa_bkpf-bukrs AND wa_bseg-belnr = wa_bkpf-belnr AND wa_bseg-gjahr = wa_bkpf-gjahr. ELSE. EXIT. ENDIF.</span> 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句
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 |
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 <span style="color:#ff6900" class="tadv-color"> WHERE bukrs = wa_bkpf-bukrs AND belnr = wa_bkpf-belnr AND gjahr = wa_bkpf-gjahr.</span> 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文を組み合わせるのが最も早くできるのではないだろうか。引き続き様々な方向で検討していきたい。
最近のコメント