パフォーマンスチューニング最終更新日: 2021年3月16日
R8 | R9

大量の選択肢を持つリストボックス・ラジオボタンをつくらない

問題点

Wagbyが提供するリストボックスやラジオボタンは、大量データの選択には向いていません。ユーザーインタフェースの操作性から、選択肢として画面に表示される数は100件以下が妥当といえます。

このリストボックス(またはラジオボタン)を読み込み専用または隠し項目とし、かつ100件を超えるデータを保持させるような設計を行った場合、内部では選択肢を用意するため大量の SQL が発行されます。このような項目を多く含むモデル定義では、選択肢のデータ量が増加するに従い、パフォーマンスに問題が生じます。

図1 大量の選択肢をもったリストボックス

検索条件にも含めない

参照先モデルのデータ数が多いリストボックス(またはラジオボタン)を検索条件に含めた場合、そのモデルの一覧表示画面を開くときに時間がかかります。親子モデル関係にある親モデルの子モデル同時表示では、子のモデルの処理が遅くなることから、結果的に親モデルの画面を開くときに時間がかかるようになります。

解決策

大量の選択肢を持つモデル参照項目はリストボックスやラジオボタンではなく「検索画面」として定義してください。特に、もともと読み込み専用または隠し項目として設定していた場合は、見た目の影響もありません。

「検索画面」は選択肢を事前に作成しないため、SQL発行数を削減することができます。

リストボックスの絞込設定の方式を見直す

問題点

Wagby では登録・更新画面でのリストボックス等の絞込方法として2通りの定義方法を提供しています。

[a] 方式は、いったん全ての選択肢データをデータベースから取得してから絞り込みを行います。そのため、大量の選択肢をもつ場合には不向きです。

[b] 方式は SQL の where 句を使って絞り込みを行うため、大量の選択肢があった場合でもパフォーマンスの問題が発生しにくいようになっています。

図2 「当社担当部署」を指定すると「当社担当者」の選択肢が変わる例

解決策

選択肢の数が多い場合は [b] 方式の利用を推奨します。

被参照モデルのサブモデルを作成する

問題点

モデルAが、モデルBを参照している関係を例に説明します。

被参照モデル(B)に繰り返しコンテナ、チェックボックス項目などが定義されているとき、モデルAから当該モデルを参照するタイミングで、モデルBのこれら項目全てを SQL を使って読み込みます。しかし、モデルA 側では、これらの項目を利用しないことがわかっている場合、この SQL 処理は不要なものです。

図3 別テーブルのjoinが必要な場合

例えば、被参照モデルに「データの変更履歴」を保持させたとします。しかし多くの場合、これを参照するモデルでは、変更履歴情報を使うことはありません。しかし処理上は、被参照モデルをアクセスするタイミングで必ずデータの変更履歴を保持する繰り返しコンテナ(これは別テーブルです)も SQL で操作するため、パフォーマンスの観点からは好ましくありません。

解決策

被参照モデルに、必要最低限の項目のみを保持したサブモデルを用意します。

図4 メインモデルとサブモデル

サブモデルには主キー、非参照項目、表示優先度項目、無効判定項目、絞込項目等のモデル参照の際に利用される最低限の項目のみを定義します。参照モデルからは、このサブモデルを使うことで、不要な処理を抑制することができます。

ビューを使う場合でもキャッシュを有効にする

問題点

外部データベースにあらかじめビューを用意しておき、Wagbyのモデルがこのビューを参照するような設計を行うことができます。

図5 ビューを参照させる

ここでビューのデータが不定期に更新される場合、Wagbyのモデルキャッシュ機構によって過去のデータを表示してしまう懸念が生じます。そのためモデルキャッシュを無効とすることができますが、これは当該モデルへの参照の都度、SQL を発行するため、パフォーマンス低下の要因になります。

解決策

次の方法をご検討ください。

  1. Wagbyのモデルキャッシュを有効とし、ジョブを使ってキャッシュ情報を定期的に消去する。
  2. データベースが提供する「マテリアライズドビュー」を使う。

詳細は"モデル > ビューの利用"をお読みください。

前後のデータにアクセスするボタンの動作

詳細画面で「前後のデータにアクセスする」ボタンを用意することができます。

Wagbyの一般的な画面操作は、(1) 検索 (2) 一覧表示 (3) 詳細表示となります。 ここで前後のデータにアクセスするボタンは、(2) の一覧表示の処理で取得した検索結果を使って、自分の前と後のデータを把握します。

この手順を踏まずに、直接 (3) の詳細表示画面へ遷移する場合、改めて内部で一覧データを取得する処理を行います。そのため、詳細画面の表示に時間を要します。

前後のデータにアクセスするボタンを無効とすることで、詳細画面の表示パフォーマンスを改善することができます。(標準では、本機能は有効となっています。)

SQL式の見直し

複雑なSQL式はパフォーマンス低下の原因になることがあります。また、SQL式の項目を一覧表示のソート項目にしないような工夫も必要です。

集合処理関数の見直し

親子モデル関係で、子モデルの要素全体に対する集合処理(COUNT や SUM など)を行なっており、第二引数に条件を指定する場合、モデル参照項目のID部を使って判断する処理は時間がかかります。子モデル一覧表示に ID 部を保持する隠し項目を用意し、この項目の値を使って判断するようにすることでパフォーマンスの向上につなげることができます。

子モデル support の COUNT 処理で、第二引数の条件を指定した式を想定します。

COUNT(${support_lp}, "${support_lp.type#id}==1")

上の条件式で #id 表記を使っています。この場合、内部でいったん ID を取得する処理を行うため、件数が多いとパフォーマンスに影響します。

support モデルの一覧表示項目に、隠し項目として上の type 項目の ID の値を(DB保存項目として)もたせておきます。これを typeHidden という項目名としたとき、次の式に変えると効果があります。

COUNT(${support_lp}, "${support_lp.typeHidden}==1")

別の案

Wagbyが提供するCOUNTやSUM関数を使わず、代わりにスクリプトを使って計算結果を求めるという方法もあります。スクリプトでは適切な検索条件をセットしてDaoを呼び出すか、または直接、SQLを記述します。(利用するデータベースが提供するCOUNT,SUM関数を使うようにします。)

スクリプトのリロード方式の変更

Wagby のスクリプトは実行時に毎回、スクリプトファイルの日付をチェックし、更新があった場合は再読み込みを行うようになっています。このチェック処理を行わないようにすることで、パフォーマンスを向上させることができます。

アプリケーションの起動時間を短縮する

ビルドされたアプリケーション(wagbyapp)は、生成されたソースコードをコンパイルした .class ファイルが WEB-INF/classes フォルダに格納されています。これを一つの jar ファイルにまとめることで、起動時間を短縮することができます。

boostコマンド

Wagbyをインストールしたフォルダ内に misc フォルダが含まれています。コマンドプロンプトを開き、misc フォルダに移動します。次のコマンドを実行します。

boost
図6 boostの実行

このタスクは WEB-INF/classes のファイル群をまとめ、WEB-INF/lib フォルダに wagbyapp.jar を生成します。WEB-INF/classes 以下の .class ファイルは削除されます。これによって起動時間が高速になります。

その後のビルド処理

その後、Designer に戻ってモデル定義を変更し、差分ビルドを行うと WEB-INF/lib/wagbyapp.jar が再び WEB-INF/classes に展開されてからコンパイル処理が行われます。(注意:この展開のための時間が余分にかかります。)

フルビルドの場合は WEB-INF/classes および WEB-INF/lib/wagbyapp.jar の両方を消去し、クリーンな状態にします。

仕様・制約

boost 後は、check_db.bat などデータベース運用のための CUI コマンドが実行できません。これらのコマンドは boost 前に実行するようにしてください。または次のコマンドで、boost 状態を元に戻すことができます。

unboost

所要時間を計測する

ログ (logs/system.log) に、ある画面操作の開始と終了を記録することができます。

2020-10-14 13:49:59 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) myShowListJfcportal|Search Start  http-nio-8921-exec-6  
2020-10-14 13:49:59 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) myShowListJfcportal|Search Finish http-nio-8921-exec-6 [23 msec] 
2020-10-14 13:50:02 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showListModel1|Search Start  http-nio-8921-exec-8  
2020-10-14 13:50:02 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showListModel1|Search Finish http-nio-8921-exec-8 [9 msec] 
2020-10-14 13:50:09 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Start  http-nio-8921-exec-9:1000  
2020-10-14 13:50:09 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Finish http-nio-8921-exec-9 [13 msec] 
2020-10-14 13:50:18 [INFO jp.jasminesoft.jfc.controller.DbUpdateBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) updateModel1|BeginUpdate Start  http-nio-8921-exec-10:1000  
2020-10-14 13:50:18 [INFO jp.jasminesoft.jfc.controller.DbUpdateBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) updateModel1|BeginUpdate Finish http-nio-8921-exec-10 [3 msec] 
2020-10-14 13:50:20 [INFO jp.jasminesoft.jfc.controller.DbUpdateBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) updateModel1|DoUpdate Start  http-nio-8921-exec-2  
2020-10-14 13:50:20 [INFO jp.jasminesoft.jfc.controller.DbUpdateBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) updateModel1|DoUpdate Finish http-nio-8921-exec-2 [16 msec] 
2020-10-14 13:50:20 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Start  http-nio-8921-exec-3:1000  
2020-10-14 13:50:20 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Finish http-nio-8921-exec-3 [4 msec] 
2020-10-14 13:50:28 [INFO jp.jasminesoft.jfc.controller.DbInsertBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) insertModel1|BeginInsert Start  http-nio-8921-exec-4  
2020-10-14 13:50:28 [INFO jp.jasminesoft.jfc.controller.DbInsertBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) insertModel1|BeginInsert Finish http-nio-8921-exec-4 [2 msec] 
2020-10-14 13:50:32 [INFO jp.jasminesoft.jfc.controller.DbInsertBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) insertModel1|DoInsert Start  http-nio-8921-exec-5  
2020-10-14 13:50:32 [INFO jp.jasminesoft.jfc.controller.DbInsertBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) insertModel1|DoInsert Finish http-nio-8921-exec-5 [61 msec] 
2020-10-14 13:50:32 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Start  http-nio-8921-exec-7:1002  
2020-10-14 13:50:32 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Finish http-nio-8921-exec-7 [4 msec] 
2020-10-14 13:50:44 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Start  http-nio-8921-exec-8:1000  
2020-10-14 13:50:44 [INFO jp.jasminesoft.jfc.controller.DbShowBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showModel1|DoShow Finish http-nio-8921-exec-8 [3 msec] 
2020-10-14 13:50:50 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showListModel1|Search Start  http-nio-8921-exec-9  
2020-10-14 13:50:50 [INFO jp.jasminesoft.jfc.controller.DbShowListBaseController perform_db] (admin@0:0:0:0:0:0:0:1|Chrome) showListModel1|Search Finish http-nio-8921-exec-9 [4 msec] 

ここで、ログの各行の最後に出力される文字列(上の例ではhttp-nio-8921-exec-<番号>)は Java 内部のスレッド名です。ある処理の開始時に "Start" が、終了時に "Finish" が含まれます。これによってスレッド名が同じであれば、開始と終了のペアを探すことができます。また、"Finish" のあとには処理時間がミリ秒単位で表示されます。

同じスレッド名が何回も再利用されます。これはJavaの挙動です。

設定方法

ビルドされたアプリケーション (wagbyapp) の WEB-INF/classes/jfcbase.properties に含まれている以下のエントリを有効にします。

先頭のセミコロンを除いて保存することで、このエントリが有効になります。
;jp.jasminesoft.jfc.controller.BaseController.isOutputThreadNameToLog=true

設定変更後、アプリケーションを再起動します。再起動後のログ出力で本設定が有効となっていることを確認してください。

ヘルパクラスのログにもスレッド名を出力する

上の設定でコントローラ処理の最初と最後にスレッド名が表示されるようになりました。この間に出力されるログについてもスレッド名を表示させることにより、同一のスレッドで行われた処理を追うことができるようになります。

アプリケーション (wagbyapp) の WEB-INF/classes/log4j2.xml を編集します。 ログフォーマット loglayout に %t を含めると、スレッド名が表示されます。例を示します。

%d{yyyy-MM-dd HH:mm:ss} [%p %c %M] %t %m%n