iPLAssを利用したアプリケーションのパフォーマンスをチューニングして最適化するためのポイントやヒントを説明します。
1. Tips
1.1. チューニングに必要なログの取得
iPLAssが出力するログの中には、以下のようなチューニングに必要な情報が記録されるログが存在します。iPLAssが標準で出力するログの詳細については、ログ(Slf4j/Logback)を参照してください。
-
Action/WebAPIの実行時間
-
閾値を設定し、それを超える実行時間の場合、WARNレベルでログ出力することが可能です(デフォルトはすべてINFOレベルで出力)。詳細は、ActionはActionMappingService、WebAPIはInterceptorService、それぞれの「LoggingInterceptor」の説明を参照してください。
-
-
Action/WebAPIの処理中に発行されるSQLの回数
-
閾値を設定し、それを超えるSQL発行回数の場合、WARNレベルでログ出力することが可能です(デフォルトはすべてINFOレベルで出力)。詳細は、ActionはActionMappingService、WebAPIはInterceptorService、それぞれの「LoggingInterceptor」の説明を参照してください。
-
-
EQLの処理時間(スロークエリログ)
-
閾値を設定し、それを超える処理時間のEQLをスロークエリと判定してWARNレベルでログ出力することが可能です(デフォルトはすべてDEBUGレベルで出力)。詳細は、ConnectionFactoryを参照してください。
-
-
検索条件にINDEXが付与されたプロパティが利用されていないEQLの事前警告
-
詳細は、ConnectionFactoryを参照してください。
-
1.2. StorageSpaceの変更による高速化
StorageSpaceとは、iPLAssで管理するEntityのデータの格納先を指します。デフォルトでは、3つのStorageSpace(ユーザー用、iPLAss標準Entity用、デフォルト)が定義されており、1つの物理テーブルに複数のEntityのデータを保持する構造になっています。詳細は、StorageSpaceを参照してください。
例えば、一部大量データが格納されるEntityが存在した場合、その他のEntityのデータを検索する際の処理時間に影響が出る可能性があります。そのような場合は、大量データが格納されるEntityを別の独自StorageSpace(物理テーブル)に格納することを検討します。
独自のStorageSpaceを利用した場合、データが格納される物理テーブルが分かれるため、統計情報の精度が高まり、より良い実行計画になることが見込まれます。また、以下のようにEntityの特性に合わせて物理テーブルの特性を変更することが可能になります。
-
数値型のプロパティが多いEntity用に数値型のカラムを300個、日付型は1個だけにしたStorageSpaceを定義する。
-
プロパティ数が少ないEntity用に、文字列型、数値型、日付型のカラムを3個ずつだけにしたStorageSpaceを定義する。
Entityの特性毎にStorageSpaceをうまく使い分けることにより、RDB上のテーブルスペースを効率的に利用することが可能になったり、汎用カラム数がオーバーした場合に利用される pg_no
による疑似レコード化(自己結合)を抑えることによる高速化が期待できます。
1.3. Entityのカラムマッピングによる高速化
デフォルトでは、Entityのプロパティ値を格納する物理テーブル上のカラムは、プロパティの型とStorageSpace定義を基にして基盤内部で自動決定されます(どのカラムにデータが格納されているかはアプリ側では判断できません)。Entityのプロパティ定義で、カラムマッピングの設定を行うことにより、StorageSpaceに紐づく物理テーブル上の特定のカラムにプロパティ値を保存することができます。詳細は、カラムマッピングを参照してください。
カラムマッピング機能を利用することにより、あるプロパティ値が物理テーブル上のどのカラムに格納されるかを判断できるようになります。よって、RDBネイティブの複合INDEXを作成したり、パーティション作成時のキーとして特定のプロパティ値を指定する等、RDBネイティブの機能を利用してチューニングを実施することが可能になります。
1.4. EQLのヒントコメント
EQLに対してヒントコメントを設定することで検索処理のチューニングを行うことが可能です。 詳細は、ヒントコメントを参照してください。
例えば、以下のようなヒントコメントによる検索処理のチューニングが考えられます。
-
EQLから変換されたSQLの実行計画を確認し、想定しているINDEXが利用されていない場合には、「index」ヒントコメントを利用し、明示的に利用するINDEXを指定します。
※ Entityのプロパティ定義にて、INDEX
、UNIQUE INDEX
のいずれかが指定されている必要が有ります。 -
EQLから変換されたSQLの実行計画を確認し、意図していない実行計画であった場合(テーブルの結合順序など)、RDBネイティブのヒント句(LEADING等)を用いて実行計画を制御し、実行計画の最適化を図ります。
1.5. EQLクエリーキャッシュ
上述したヒントコメントの「cache」ヒントコメントを設定することにより、EQLの実行結果をキャッシュすることが可能です。
クエリキャッシュには、同一トランザクション内キャッシュである TRANSACTION
と、共有キャッシュである GLOBAL
が存在します。 GLOBAL
を利用する場合は、Entity定義の queryCache
を有効化した上で、EQLの「cache」ヒントコメントを設定する必要があります。
EQLクエリーキャッシュは、繰り返し実行されるようなEQL(キャッシュヒット率が高い)には有効ですが、実行頻度の少ないEQL(キャッシュヒット率が低い)の場合には、効果が低いため、キャッシュヒット率が高いEQLを見極めつつ設定を検討してください。また、EQL内で参照しているEntity定義のデータが1件でも更新された場合、(キャッシュされた検索結果に含まれない場合でも)キャッシュは破棄されるため、更新頻度が高いEntityはEQLクエリーキャッシュではキャッシュしないことを推奨します。
キャッシュは、APサーバ上のメモリに保持されるため、メモリ消費量を確認しつつ、設定を検討してください。 |
1.6. Entity権限の参照、登録、更新、削除可能範囲条件の注意事項
Entity権限の参照、登録、更新、削除可能範囲条件を設定した場合、セキュリティ設定として、EQL実行時のWHERE条件や当該Entityが結合される場合の結合条件に指定した条件が自動付与されます。条件内で参照プロパティを多用している場合は、EQLが複雑になり、EQLから変換後のSQLもより複雑になります。極力、参照プロパティは利用しないことを推奨します。もし、必要な場合でもEntity内のプロパティに置き換えられないか検討してください。
汎用データ操作画面(GEM/MDC)の検索画面では、EntityViewの検索画面の設定で「Entity権限における限定条件の除外設定」を指定することが可能です。参照先Entityの参照可能範囲条件を付与せずとも、当該Entityの参照可能範囲条件やデフォルト検索条件を付与することで、当該ロールの参照可能範囲が適切に絞り込める場合には、参照先Entityの限定条件の除外設定を行うことで結合条件が単純化され、パフォーマンスの向上が見込めます。 |
1.7. ロール条件や各種権限条件による注意事項
ロール条件及び、Entity(参照、登録、更新、削除可能範囲条件)、Action(許可条件)、WebApi(許可条件)、Workflow(許可条件)の各種権限条件は、権限チェックのため、該当処理を実行する度に呼び出される処理となります。そのため、条件内でDB検索処理や複雑な処理を組み込んだ場合、処理速度に影響します。
DB検索が必要な場合は、事前にデータをキャッシュしておくなど、DB検索の回数を減らすことを検討してください。
1.8. 汎用データ操作画面の検索画面における注意事項
汎用データ操作画面(GEM/MDC)の検索画面では、対象Entityのデータ件数が多くなることが見込まれる場合は考慮が必要です。デフォルトの設定では、検索実行時には、ページングに利用するための全件カウントと検索条件を基にした検索処理の2つが実行されます。検索条件未指定などのデータ件数が絞り込めない検索や、INDEX項目を利用した絞り込みができない検索を行った場合に検索処理の速度が遅くなることがあります(開発時など、データ件数が十分に多くない状況下では、速度が遅いことに気が付きにくいのでご注意ください)。
軽減策として、以下を検討してください。
-
検索条件に十分な絞り込みができる必須項目を設け、当該項目にINDEX設定を行う。
-
EntityViewの検索画面の設定で「ページングを非表示」、「件数を非表示」を有効化する。これらの項目を有効化した場合、全件カウント処理がスキップされます。
合わせて、カスタムロジックでEQLを発行する際にも同様のことが言えますので、ご注意ください。
AutoNumber型プロパティ、String型プロパティの検索条件項目が指定された場合、デフォルトではLIKEの中間一致の条件が付与されます。デフォルトの中間一致条件の場合は、INDEXが利用されない為、INDEXを利用して検索したい場合は、PropertyEditorの設定項目の「完全一致で検索」を有効化して完全一致条件としてください。 |
1.9. Expression型のプロパティ利用時の注意事項
Expression型プロパティの値は、実体を持たず、式計算により算出されるため、利用する場合に検索処理のパフォーマンスに影響が出る可能性があります。
-
Expression型のプロパティにはINDEXを定義できないため、検索条件の絞り込み項目に設定しても、検索が速くなることはありません。
-
Expression型のプロパティの値は検索時に式計算により算出されるため、クエリを実行する際に負荷がかかります。
特に負荷がかかる例として、Expression型で相関サブクエリを利用する場合があります。
具体的な例として、
-
見積Entity(Estimate)に参照プロパティ(detail)として、明細Entity(Detail)を多重度*で定義
-
明細Entity(Detail)に参照プロパティ(estimate)として、見積Entity(Estimate)を多重度1で定義
といったEntity構造の場合に、明細の個数をカウントするExpression型プロパティを見積Entity側に定義するといったケースが挙げられます。
式例 : (select count() from Detail on .oid = estimate.oid )
上記のようなパターンの改善策として、Expression型を利用せず、実体としてプロパティを定義し、更新時にEntityEventListenerなどで値を事前計算して更新する等の方法を検討してください。
1.10. AutoNumber型の採番ルールの注意事項
Entity定義において、AutoNumber型を利用する際に、採番ルールを「同一トランザクションで採番」とした場合、同時にデータ登録処理が実行された場合には、前処理がコミットされるまで待ってしまうため、待ち時間が増えてしまいます。
採番の飛び番を許容する場合は、「別トランザクションで採番」を設定するようにしてください。
1.11. Entityデータのバージョン管理利用時の注意事項
Entity定義において、データのバージョン管理を利用する際、検索処理時のEQL(SQL)の複雑性を軽減するため、要件が許す限り、STATE BASE
方式、もしくは SIMPLE TIME BASE
方式を利用することを推奨します。
また、現在無効なバージョン含めて、データはすべて同じ物理テーブルに保存されるため、大量のデータが登録されることが予見される場合は、無効となった利用しないバージョンのデータを定期的にメンテナンス(削除、別Entity・物理テーブルへの移動など)することを検討してください。
1.12. Entity設計時の注意事項
Entityの設計をする際には、正規化をすることが多いですが、過度な正規化はパフォーマンスへの悪影響が懸念されます。
iPLAssの場合、Entity定義の作成・変更が容易なため、気が付かず過度に正規化してしまうこともあるためご注意ください。Entity設計時には、パフォーマンスを考慮してあえて非正規化することも検討してください。
正規化して参照プロパティが増加した場合、EQLからSQLへの変換時に関連テーブル(obj_ref
テーブル)が挟まるので、結合するテーブル数が増えます。結果、RDB側の制限にてSQL自体が実行できなくなる場合や、パフォーマンスへの悪影響が出る場合があります。
1.13. 非同期処理の活用
設計時に非同期処理に適した処理がないか検討してください。特に負荷集中時にボトルネックとなる処理を非同期化することを検討します。ボトルネックとなる処理をキューに溜めておき非同期で逐次処理することで、スケールアップ、スケールアウトといった物理的な負荷分散ではなく、時間的に負荷分散することができます。結果、負荷のピークを平準化することができます。
具体的な例として、
-
処理時間がかかる集計処理を、集計ボタンを押してからレスポンスを返すまでの一つの処理とするわけではなく、集計処理の受付だけを実施し、時間のかかる集計処理自体は非同期で実行。その後、結果を取得する機能を別途用意し、集計結果を取得する。
-
ピーク性がある処理(チケット申込など)は、同期処理は受付のみとし、複雑な処理や、メール送信処理などを非同期で処理する。場合によっては、処理先を別サーバで実施する事も検討して、負荷集中してもスケールしやすくする。
といったケースが挙げられます。
非同期処理の設定は、RdbQueueServiceにてキューの設定を実施し、非同期処理(AsyncCommand)を定義、Command処理を実装します。
1.14. 大量データの一括更新の高速化
データ移行などの大量データを一括で登録、更新、削除する際には、バルク更新処理を活用することができます。
バルク更新処理の方法には、
-
EntityExplorerによる画面による方法
-
BatchTool Importを利用する方法
-
EntityManagerのbulkUpdateメソッドを利用することにより、バルク更新処理自体をプログラムから呼び出す方法
がありますので、必要に応じて利用を検討してください。
1.15. ログイン処理カスタマイズ時の注意点
ログイン認証コマンドをカスタマイズして、ログイン以外の処理を組み込む場合、トップページが表示されるまでの処理時間が長くなるため、注意が必要です。ログインする際に必要な処理かどうかの判断をした上でログイン以外の処理を組み込むようにしてください。
例えば、トップページに表示する内容の取得のためにDB検索をしている場合は、トップページ表示後に非同期でデータ取得する方法の検討や、データ自体を事前キャッシュして、ログイン時はキャッシュしたデータを取得する等の検討を行ってください。
1.16. 設定ファイル(mtp-service-config.xml)のチューニング
設定ファイルのデフォルト値をそのまま利用すると十分な性能を発揮できない場合があります。適切な値に設定して利用してください。
以下、特に設定内容の検討が必要な箇所となります。
-
HttpClientConfigのhttpコネクションのプールの最大数、ドメイン単位のhttpコネクションの最大数
※ HttpClientConfigの設定は、複数箇所に設定されているので、各箇所の設定の見直しを行ってください。 -
CacheServiceに設定されているauthBuiltin、metadataのキャッシュの有効期限
-
RdbQueueService WorkerConfigのキューを並列で処理するワーカーの数、キューに割り当てるワーカーの数
-
ODataServiceに設定されているODataのQuery操作時のデフォルトのページングサイズ
-
MailServiceのSendGridMailServiceImplの設定にて、checkBounce(バウンスリスト、ブロックリストチェック)の有効/無効
※ デフォルトでは、有効になっています。バウンスチェックの処理は遅いため、短時間で大量にメール送信することが見込まれる場合は、無効に設定し、定期的に手動でチェックするといった運用で対処できないかを検討してください。 -
ConnectionFactoryに設定されているDataSourceのコネクションプールの最大数
※ コネクションプール接続の最大プール数の推奨値を参考に設定してください。