たとえば請求書の一覧を表示する場合、請求書テーブルには部門IDが保存されていて部門名を部門テーブルから持ってくる、ような場面がある。次の3通りのやり方について考察してみよう。自動リレートは使わないという前提で。
1)請求書を1件持ってくるたびに部門テーブルをクエリーして部門名を取得する
2)部門テーブルを全件クエリーして配列に取っておいて、Find in array()で部門名を取得する
3)1)をサーバサイドで実行して結果の配列を取得する
請求書テーブルをクエリーして請求書一覧を表示するBL01_lstBL_makeというメソッドがあるとして。サーバ上で実行するメソッドBL01_lstBL_make_onServerを呼ぶ。引数に配列のポインタを渡す。配列はv17以降はオブジェクトの配列がよい。
親メソッド:BL01_lstBL_make
…
ARRAY OBJECT($aryObjBL)
$cnt:=BL01_lstBL_make_onServer($aryObjBL) //サーバ上で実行するメソッドを実行して配列のポインタを受け取る
//配列を確保
ARRAY LONGINT(vBL01_lstBL_ID;$cnt)
ARRAY TEXT(vBL01_lstBL_BU_NAME;$cnt)
…
//配列に値を代入
for($i;1;$cnt)
vBL01_lstBL_ID{$i}:=$aryObjBL{$i}.id
vBL01_lstBL_BU_ID{$i}:=$aryObjBL{$i}.bu_id //部門コードはBLから取得
vBL01_lstBL_BU_NAME{$i}:=$aryObjBL{$i}.bu_name //部門テーブルからジョインして取得済み
…
end for
サブメソッド:BL01_lstBL_make_onServer
C_POINTER($1;$aryObjPtr)
$aryObjPtr:=$1
C_OBJECT($objBL)
query(….)
$numOfRecs:=Records in selection([BILL])
for ($i;1;$numOfRecs)
GOTO SELECTED RECORD([BILL};$i)
$objBL:=New object
$objBL.id:=[BILL]BL_ID
$objBL.bu_id:=[BILL]BL_BU_ID
bu_name:=BU_GetName([BILL]BL_BU_ID) //堂々とクエリしているがサーバ上で実行すると速い
$objBL.bu_name:=$bu_name
…
APPEND TO ARRAY($aryObjPtr->;$objBL)
end for
$0:=$numOfRecs
BL01_lstBL_make_onServerのメソッド属性で「サーバ上で実行」をチェックしておくこと。
この方法だと、転送するデータは表示データの数とほぼ同じになるため転送は速い。クエリーが遅いかどうかはBL01_lstBL_make_onServerを呼び出しているところにトレースポイントを入れて実行してみればすぐわかる。
当社の最近の事例(v18)で120個の集計マスを計算して4D View proのエリアに表示する、というロジックがあった。「サーバ上で実行」せずにセットを使って実装、クエリー回数は最適化していた。スタンドアロンだと瞬時に表示されていたのがC/Sで実行すると15秒くらいかかる。コードを見直して、ジョインも含めたDBアクセスをすべてサーバサイドで行う、という修正の結果、15秒が瞬時(1秒以内)に改善された。
高速化のポイント:クエリーはすべてサーバサイド