18 パフォーマンスの向上
この章の内容は次のとおりです。
ユース・ケース
ユーザーは、TopLinkが有効なアプリケーションのパフォーマンスの向上を希望しています。
解決方法
TopLinkには、キャッシュなど、パフォーマンスを向上させる多数のオプションがあります。また、問合せで結合フェッチを使用するなど、特定の機能のパフォーマンスを向上させる方法があります。
コンポーネント
-
TopLink 12c (12.1.2.0.0)以上。
注意:
TopLinkのコア機能は、オープン・ソースのEclipse Foundationの永続性フレームワークであるEclipseLinkによって提供されています。EclipseLinkでは、Java Persistence API (JPA)、Java Architecture for XML Binding (JAXB)、および標準に基づいたその他の永続性テクノロジと、それらの標準の拡張が実装されます。TopLinkには、EclipseLinkのすべてに加え、Oracleの追加機能が含まれています。
-
EclipseLink 2.4以降。
サンプル
関連情報については、次のEclipseLinkの例を参照してください。
パフォーマンス機能
オブジェクト・キャッシング
EclipseLinkキャッシュは、クラスと主キーの値に基づいて最近読み取られたり書き込まれたオブジェクトがストアされる、インメモリー・リポジトリです。キャッシュは、最近の読取りまたは書込みオブジェクトを保持し、メモリー内でそれらにアクセスしてデータベースへのアクセスを最小限にすることで、パフォーマンスの向上を助けます。
キャッシングでは、次のことを行えます。
-
キャッシュの無効化と呼ばれるプロセスで、キャッシュの存続期間および時間を設定できます。
-
キャッシュ・タイプ(Weak、Soft、SoftCache、HardCache、Full)をエンティティごとに構成できます。
-
エンティティごとにキャッシュ・サイズを構成できます。
-
クラスタ化されたキャッシュを調整できます。
キャッシング注釈
EclipseLinkには、次のエンティティ・キャッシング注釈が定義されています。
-
@Cache
-
@TimeOfDay
-
@ExistenceChecking
EclipseLinkには、EclipseLinkキャッシュの構成に指定できる永続性ユニット・プロパティも多数用意されています(『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の永続性プロパティの拡張のリファレンスに関する項を参照してください)。これらのプロパティを注釈のかわりに使用したり、注釈を補完したりできる場合があります。
@Cache注釈の使用
EclipseLinkでは、パフォーマンスを向上させ、オブジェクトIDを維持するアイデンティティ・マップを使用して、オブジェクトをキャッシュします。エンティティ・クラスで@Cache
注釈を使用すれば、キャッシュおよびその動作を制御できます。例18-1に、この注釈の実装方法を示します。
例18-1 @Cache注釈の使用
@Entity @Table(name="EMPLOYEE") @Cache ( type=CacheType.WEAK, isolated=false, expiry=600000, alwaysRefresh=true, disableHits=true, coordinationType=INVALIDATE_CHANGED_OBJECTS ) public class Employee implements Serializable { ... }
オブジェクト・キャッシュおよび@Cache
注釈の使用方法の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@Cacheに関する項を参照してください。
問合せ
問合せの範囲、返されるデータ量、およびデータが返される方法はすべて、EclipseLinkが有効になっているアプリケーションのパフォーマンスに影響を与える可能性があります。EclipseLinkの問合せメカニズムでは、次の機能を提供して問合せパフォーマンスを向上しています。
この項では、これらの機能により、どのようにパフォーマンスが向上するかを説明します。
読取り専用問合せ
EclipseLinkでは、eclipselink.read-only
ヒント、QueryHint
(@QueryHint
)を使用して、読取り専用の結果を問合せから取得します。リクエストされたエンティティ・タイプが共有キャッシュにストアされるような非トランザクションの読取り操作の場合は、デタッチされたコピーではなく、共有インスタンスが返されるようにリクエストできます。
読取り専用の問合せの詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』で読取り専用のヒントに関する項を参照してください。
結合フェッチ
結合フェッチでは、ソース・オブジェクトと同じ問合せにある関連オブジェクトの結合および読取りを有効にすることにより、パフォーマンスを向上します。例18-2に示すように、@JoinFetch
注釈を使用して、結合フェッチを有効にします。この例では、Employee
フィールドmanagedEmployees
を@JoinFetch
注釈で指定する方法を示しています。
例18-2 結合フェッチの有効化
@Entity
public class Employee implements Serializable {
...
@OneToMany(cascade=ALL, mappedBy="owner")
@JoinFetch(value=OUTER)
public Collection<Employee> getManagedEmployees() {
return managedEmployees;
}
...
}
結合フェッチの詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@JoinFetchに関する項を参照してください。
バッチ読取り
eclipselink.batch
ヒントは、EclipseLinkにバッチ処理情報を提供して、関連オブジェクトに対する後続の問合せでオブジェクトを1つずつ取得したり、大規模な1つの結合読取りとして取得せずに、それをバッチ内で最適化できます。バッチ読取りでは、重複データの読取りが回避されるので、結合よりも効率的です。バッチ処理は、SELECT句にオブジェクトが1つしかない問合せに対してのみ実行できます。
フェッチ・サイズ
多数のオブジェクトを返す大規模な問合せがある場合は、選択条件を満たすために必要なデータベースのヒット数を減らすことにより、パフォーマンスを向上できます。これを行うには、eclipselink.jdbc.fetch-size
ヒントを使用します。このヒントには、より多くの行が必要になる場合(JDBCドライバのサポート・レベルに従って)に、データベースからフェッチする行数を指定します。ほとんどのJDBCドライバのデフォルト・フェッチ・サイズは10になっています。そのため、1000個のオブジェクトを読み取る場合、フェッチ・サイズを256に増やすと、問合せ結果のフェッチに要する時間が大幅に短縮される場合があります。最適なフェッチ・サイズが常に明白であるとはかぎりません。通常は、予想される総結果サイズの半分または4分の1がフェッチ・サイズとして最適です。結果セットのサイズが不確かな場合に、誤ってフェッチ・サイズの設定を大きく、または小さくしすぎると、パフォーマンスが低下する可能性がありますので、注意してください。
ページ区切り
ページング処理が遅いと、アプリケーションの負荷が大幅に高くなる場合がありますが、EclipseLinkには次のようなページング結果が向上する様々な解決策が用意されています。
-
問合せの実行時に最初に取得する行数および最大行数を構成できます。
-
基準と一致するすべてのID値に対してデータベースで問合せを実行してから、ID値を使用して特定のセットを取得できます。
-
問合せヒントを使用して、
ScrollableCursor
オブジェクトを問合せから返すようにEclipseLinkを構成できます。これにより、問合せの結果セットにデータベース・カーソルが返されるので、クライアントでページごとに結果をスクロールできるようになります。
ページング・パフォーマンスの向上の詳細は、次のEclipseLinkオンライン・ドキュメントの『How to use EclipseLink Pagination』を参照してください。
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination#How_to_use_EclipseLink_Pagination
キャッシュの使用方法
EclipseLinkでは、永続性ユニット全体を範囲とする共有キャッシュ・メカニズムを使用しています。特定の永続性コンテキストで操作が完了すると、結果が共有キャッシュに再びマージされて、他の永続性コンテキストが使用できるようになります。これは、エンティティ・マネージャおよび永続性コンテキストがJava SEまたはJava EEで作成されているかどうかに関係なく行われます。エンティティ・マネージャを使用して永続化または削除されたエンティティでは、常にキャッシュとの整合性が保たれます。
eclipselink.cache-usage
ヒントを使用すれば、問合せとEclipseLinkキャッシュがどのようにやり取りを行うかの方法を指定できます。詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のキャッシュの使用方法に関する項を参照してください。
マッピング
インダイレクション(遅延ロード)
デフォルトでは、EclipseLinkは永続オブジェクトを取得する際に、そのオブジェクトが参照する依存オブジェクトをすべて取得します。リレーションシップ・マッピングによってマップされた属性に対してインダイレクション(遅延ロード、遅延読取りおよびジャストインタイム読取りとも呼びます)を構成すると、EclipseLinkでは、参照オブジェクトのプレースホルダとしてインダイレクション・オブジェクトが使用されます。その属性にアクセスするまで、従属オブジェクトの読取りはEclipseLinkによって遅延されます。その結果、アプリケーションにとって重要なのは取得されたオブジェクトの内容のみであり、関連オブジェクトの内容は重要でないという場合は特に、パフォーマンスが大幅に向上します。
EclipseLinkは、Value Holderインダイレクション、透過インダイレクト・コンテナ・インダイレクション、およびプロキシ・インダイレクションなど、様々なタイプのインダイレクションをサポートします。
読取り専用オブジェクト
クラスを読取り専用に宣言すると、そのクラスのクローンの作成もマージも行われないので、パフォーマンスが大幅に向上します。addReadOnlyClass()
を使用すれば、作業ユニットのコンテキスト内でクラスを読取り専用として宣言できます。
-
単一の作業ユニットに対して読取り専用クラスを構成するには、そのクラスを
addReadOnlyClass()
の引数として指定します。myUnitofWork.addReadOnlyClass(B.class);
-
複数のクラスを読取り専用に構成するには、それらのクラスをベクトルに追加して、そのベクトルを
addReadOnlyClass()
の引数として指定します。myUnitOfWork.addReadOnlyClasses(myVectorOfClasses);
パフォーマンスを向上させるための読取り専用オブジェクトの使用方法の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@ReadOnlyに関する項を参照してください。
ウィービング
ウィービングは、コンパイル済のJavaクラスのバイトコードを操作する方法です。EclipseLink JPA永続性プロバイダでは、ウィービングを使用して、遅延ロード、変更追跡、フェッチ・グループ、内部最適化などに対して、JPAエンティティとPlain Old Java Object (POJO)クラスの両方を拡張します。ウィービングは、実行時の動的実行、エンティティのロード時の実行、エンティティの.class
ファイルの後処理によるコンパイル時の静的実行のいずれかで実行できます。EclipseLinkのデフォルトでは、可能な場合は常に動的ウィービングが使用されます。これは、EclipseLinkエージェントが構成されている場合のJava EE 5/6アプリケーション・サーバーおよびJava SEが含まれます。動的ウィービングは構成しやすく、プロジェクトのビルド・プロセスを変更する必要がないので、動的ウィービングをお薦めします。
アプリケーションのパフォーマンスを向上させるためにウィービングを使用する方法の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のウィービングに関する項を参照してください。
トランザクション
データ・トランザクション時のパフォーマンスを最適化するには、変更追跡を使用します。変更追跡では、トランザクション中に発生した変更をEclipseLinkが検出する方法をチューニングできます。エンティティ・タイプが異なると、アクセス・パターンも設定も異なるので、エンティティ・タイプの使用パターンおよびデータ変更パターンに基づいて戦略を選択します。
例18-3に示すように、@ChangeTracking
注釈を使用して、変更追跡を有効にします。
例18-3 変更追跡の有効化
@Entity
@Table(name="EMPLOYEE")
@ChangeTracking(OBJECT) (
public class Employee implements Serializable {
...
}
変更追跡の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@ChangeTrackingに関する項を参照してください。
データベース
EclipseLinkのデータベース・パフォーマンス機能には、次があります。
この項では、これらの機能を説明します。
接続プーリング
データ・ソースへの接続の確立には時間がかかるため、接続プールにある接続を再使用すれば、パフォーマンスを向上できます。EclipseLinkは、接続プールを使用して、サーバーおよびクライアント・セッションで使用される接続を管理および共有します。この機能により、必要な接続数が減り、アプリケーションで多くのクライアントをサポートできるようになります。
デフォルトでは、EclipseLinkセッションは内部接続プールを使用します。これらのプールでは、表示専用でデータの変更が頻繁ではないデータを読み取るアプリケーション用の読取り接続の作成を最適化できます。また、ワークベンチを使用して、デフォルト(書込み)および読取りの接続プールを構成したり、オブジェクト・アイデンティティまたは他の目的のために追加の接続プールを作成することもできます。
内部接続プールに加えて、次のいずれかのタイプの接続プールを使用するようにEclipseLinkを構成することもできます。
-
外部接続プール。外部トランザクション・コントローラ(JTA)と統合するには、このタイプの接続プールを使用する必要があります。
-
デフォルト(書込み)および読取り接続プール。
-
シーケンス接続プール。表順序付け(つまり、非ネイティブ順序付け)が必要なアプリケーションで、外部トランザクション・コントローラを使用している場合には、これらのタイプのプールを使用します。アプリケーション固有の接続プール。EclipseLinkの内部接続プールをセッションで使用している場合は、アプリケーションの目的に従って、これらの接続プールを作成して使用できます。
EclipseLinkで接続プールを使用する方法の詳細は、『Oracle TopLinkの理解』の次のトピックを参照してください。
-
「接続の理解」
-
「接続プールの理解」
パラメータ化されたSQLとSQL文のキャッシュ
パラメータ化されたSQLを使用すれば、SQL問合せの全体の長さが、JDBCドライバまたはデータベース・サーバーで決められた文の長さ制限を超えることを防げます。パラメータ化されたSQLをプリコンパイル文のキャッシュとともに使用すると、コール頻度の高い問合せのSQLがデータベースのSQLエンジンによって解析およびプリコンパイルされる回数が減少し、パフォーマンスが向上します。
デフォルトでは、EclipseLinkはパラメータ使用のSQLは有効にしますが、プリコンパイルされたSQL文のキャッシュは有効にしません。内部接続プールの使用時はEclipseLinkで、外部接続プールの使用時はデータ・ソースで、文のキャッシュを有効にし、アプリケーションに適した文のキャッシュ・サイズを指定する必要があります。
パラメータ化されたSQLを有効にするには、ドメイン・クラスと同じパスにあるpersistence.xml
ファイルに次の行を追加します。
<property name="eclipselink.jdbc.bind-parameters" value="true"/>
パラメータ化されたSQLを無効にするには、value=
をfalse
に変更します。
パラメータ化されたSQLおよび文のキャッシュの使用方法の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のjdbc.bind-parametersに関する項を参照してください。
バッチ書込み
異機種間バッチ書込みは、EclipseLinkが複数の異機種間の動的SQL文を単一バッチとして実行されるデータベースに送信することを可能にする最適化です。バッチ書込みは、各トランザクションで複数の書込みを実行するアプリケーションでの使用に最適です。
バッチ書込みを構成するには、eclipselink.jdbc.batch-writing
プロパティとeclipselink.jdbc.batch-writing.size
プロパティをpersistence.xml
ファイルに組み込みます。次の例は、Oracle JDBCドライバで使用できるOracleのネイティブ・バッチ書込み機能を有効にし、バッチ・サイズを150文に構成します。
<property name="eclipselink.jdbc.batch-writing" value="Oracle-JDBC"/> <property name="eclipselink.jdbc.batch-writing.size" value="150"/>
様々なバッチ・オプションがサポートされていて、カスタムのバッチ実装も使用できます。バッチ書込みプロパティの詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のbatch-writing
およびbatch-writing.size
に関する項を参照してください。
Exalogicでのバッチ書込み使用の詳細は、「タスク4: Exalogicでの異機種間バッチ書込みの構成」を参照してください。
シリアライズ・オブジェクト・ポリシー
シリアライズ・オブジェクト・ポリシーは、EclipseLinkが私有の(およびネストされた私有の)エンティティおよび要素コレクションとともにエンティティ・オブジェクト全体をデータベースの追加フィールドに書き出すことができる最適化です。シリアライズ・オブジェクト・ポリシーは、特定の状況でデータベースからのフェッチを最適化し、データベース読取りを高速化し、中間層CPUおよびネットワーク・アクセスを削減します。
シリアライズ・オブジェクト・ポリシーは、読取り専用またはほぼ読取り専用のアプリケーションに最適で、すべての依存エンティティおよび要素コレクションをロードするエンティティにのみ使用します。シリアライズ・オブジェクト・ポリシーを使用する場合、データベース書込み操作(挿入および更新)の速度は遅くなり、私有データを含まないオブジェクトに対する問合せの速度も遅くなります。「単純なシリアライズ・オブジェクト・ポリシーの例」を参照してください。これは、パフォーマンスを向上するためにシリアライズ・オブジェクト・ポリシーを使用するのが最適なのはどのようなときかについての例を示します。
次に示す特徴を持つ非常の多くの集計を含む複雑なオブジェクトに対してのみシリアライズ・オブジェクト・ポリシーの使用を検討してください。
-
複数のデータベース行が1つのJavaオブジェクトにマップされている
-
データベースからオブジェクトが読み取られるとき、これらの行はすべて同時に読み取られる(インダイレクションを使用しないか、またはすべてのインダイレクションが常にトリガーされる)。シリアライズ・オブジェクト・ポリシー・フィールドに含まれていないその他のフィールドにトリガーされないインダイレクションが存在する場合があります。
-
バージョニングが使用される場合、任意のマップされた行の更新または削除(あるいは新しい行の挿入)を行うと、オブジェクトのバージョンが増分される。
-
オブジェクトを削除すると、すべての行が削除される。
-
集計の構造が不規則だと、その他の一般的な最適化(結合フェッチ、バッチ読取りなど)を使用できる可能性が低くなる。
シリアライズ・オブジェクト・ポリシー構成
シリアライズ・オブジェクト・ポリシーは、エンティティまたはマップされたスーパークラスで@SerializedObject
注釈を使用するか、SerializedObjectPolicy
インタフェースの実装を渡すことにより有効化されます。このインタフェースの実装を提供する必要があります。デフォルトの実装はありません。注釈には、データベースのオブジェクトに対する列名を定義するフィールドも含まれます。デフォルトの列名はSOP
です。
例18-4は、シリアライズ・オブジェクト・ポリシーを有効にし、デフォルトの列名をオーバーライドし、オプティミスティック・ロックをcascade
に設定します。このようにすると、データベースのシリアライズ・オブジェクト・ポリシー・フィールドを最新に保持することによってパフォーマンスを向上できます。
注意:
シリアライズ・オブジェクト・ポリシーがエンティティに設定されると、同じフィールドのポリシーがすべての継承エンティティに設定されます。
例18-4 注釈を使用したシリアライズ・オブジェクト・ポリシーの有効化
@Entity @SerializedObject(MySerializedObjectPolicy.class) @OptimisticLocking(cascade = true) public class Employee implements Serializable { ... @Entity @SerializedObject(MySerializedObjectPolicy.class, column = @Column(name="ADDR_SOP")) @OptimisticLocking(cascade = true) public class Address implements Serializable { ...
例18-5は、eclipselink-orm.xml
ファイルでシリアライズ・オブジェクト・ポリシーを有効化します。
例18-5 eclipselink-orm.xmlを使用したシリアライズ・オブジェクト・ポリシーの有効化
<entity class="Employee"> <optimistic-locking cascade="true"> <serialized-object class="MySerializedObjectPolicy"> </entity> <entity class="Address"> <optimistic-locking cascade="true"> <serialized-object class="MySerializedObjectPolicy"> <column name="ADDR_SOP"/> </serialized-object> </entity>
例18-6は、カスタマイザ(セッションまたはディスクリプタ)でシリアライズ・オブジェクト・ポリシーを有効化します。
例18-6 カスタマイザでのシリアライズ・オブジェクト・ポリシーの有効化
if (descriptor.hasSerializedObjectPolicy()) { MySerializedObjectPolicy sop = (MySerializedObjectPolicy)descriptor. getSerializedObjectPolicy(); // to compare pk cached in SOP Object with pk read directly from the row from //pk field(s) (false by default): sop.setShouldVerifyPrimaryKey(true); // to NOT compare version cached in SOP Object with version read directly from // the row from version field (true by default): sop.setShouldVerifyVersion(false); // to define recoverable SOP (false by default): sop.setIsRecoverable(true); }
ディスクリプタ・カスタマイザを使用するには、クラスを定義し、@Customizer
注釈を使用してこのクラスを指定します。
public class MyDescriptorCustomizer implements org.eclipse.persistence.config.DescriptorCustomizer { public void customize(ClassDescriptor descriptor) throws Exception { ... } } ... @Customizer(MyDescriptorCustomizer.class) public class Employee implements Serializable {...
セッション・カスタマイザを使用してすべてのディスクリプタを同時に達成するには、永続ユニットのプロパティでこれを指定します。
public class MySessionCustomizer implements org.eclipse.persistence.config.SessionCustomizer { public void customize(Session session) throws Exception { for (ClassDescriptor descriptor : session.getDescriptors().values()) { ... } } } <property name="eclipselink.session.customizer" value="MySessionCustomizer"/>
シリアライズ・オブジェクト・ポリシーが有効な場合、読取り問合せ(検索、リフレッシュなど)は、自動的にシリアライズ・オブジェクトを使用します。シリアライズ・オブジェクト列にnull
または廃止されたバージョンのオブジェクトが含まれる場合、シリアライズ・オブジェクト・ポリシーを使用している問合せは例外をスローするか、他のフィールドすべてが同様に読み込まれている場合は、これらのフィールドを使用してオブジェクトを構築します(シリアライズ・オブジェクト・ポリシーが使用されていない場合も同様)。
シリアライズ・オブジェクトの問合せを無効にするには、問合せヒントの一部としてSERIALIZED_OBJECT
プロパティをfalse
に設定します。次に例を示します。
Query query = em.createQuery("SELECT e FROM Employee e") .setHint(QueryHints.SERIALIZED_OBJECT, "false");
次の例は、シリアライズ・オブジェクトの検索の無効化を示しています。
Map hints = new HashMap(); hints.put("eclipselink.serialized-object", "false"); Employee emp = em.find(Employee.class, id, hints);
シリアライズ・オブジェクト・ポリシーを使用するアプリケーションでは、結果セットのアクセスの最適化の使用も検討する必要があります。シリアライズ・オブジェクト・ポリシー・フィールドがキャッシュ済でその問合せがリフレッシュ問合せではない場合、問合せ時にこの最適化を使用して、時間がかかるシリアライズ・オブジェクト・ポリシー・フィールド(大きい場合がある)の読取りを回避します。この最適化を使用すると、結果セットから主キーのみが取得され、キャッシュ済オブジェクトを使用できない場合に追加の値のみを取得します。結果セットのアクセスの最適化を有効にするには、persistence.xml
ファイルでeclipselink.jdbc.result-set-access-optimization
永続ユニットのプロパティをtrue
に設定します。次に例を示します。
<property name="eclipselink.jdbc.result-set-access-optimization" value="true"/>
単純なシリアライズ・オブジェクト・ポリシーの例
次のオブジェクト・モデルの例について考えてみます。
@Entity(name="SOP_PartOrWhole") @Table(name="SOP_PART_OR_WHOLE") @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @Index(columnNames={"LEFTPART_ID", "RIGHTPART_ID"}) public abstract class PartOrWhole implements Serializable { @Id @GeneratedValue(strategy=GenerationType.TABLE) public long id; protected String description = ""; @OneToOne(cascade=CascadeType.ALL, orphanRemoval=true) protected Part leftPart; @OneToOne(cascade=CascadeType.ALL, orphanRemoval=true) protected Part rightPart; } @Entity(name="SOP_Whole") @DiscriminatorValue("W") @SerializedObject(MySerializedObjectPolicy.class) @NamedQueries({ @NamedQuery(name="findWhole", query="Select w from SOP_Whole w where w.id = :id", hints= @QueryHint(name="eclipselink.serialized-object", value="false")), @NamedQuery(name="findWholeSOP", query="Select w from SOP_Whole w where w.id = :id"), }) public class Whole extends PartOrWhole { } @Entity(name="SOP_Part") @DiscriminatorValue("P") public class Part extends PartOrWhole { }
前述のデータ・モデルでは、任意の数の(ネストされた)Part
オブジェクトを持つWhole
オブジェクトの構造が許可されます。次に例を示します。
-
1レベル:
Whole
オブジェクトには、左と右のPart
オブジェクトが含まれています(全部で3オブジェクト)。 -
2レベル:
Whole
オブジェクトには左と右のPart
オブジェクトが含まれていて、Part
オブジェクトのそれぞれに左と右のPart
オブジェクトが含まれています(全部で7オブジェクト)。 -
3レベル:
Whole
オブジェクトには左と右のPart
オブジェクトが含まれていて、Part
オブジェクトのそれぞれに左と右のPart
オブジェクトが含まれていて、さらにそのそれぞれに左と右のPart
オブジェクトが含まれています(全部で15オブジェクト)。 -
n
レベル: (全部で2n
+1-1オブジェクト)
前述のデータ・モデルのパフォーマンスは、モデルのレベル数が増えるにつれて向上します。次に例を示します。
-
1レベル: パフォーマンスはシリアライズ・オブジェクト・ポリシーなしの場合より低下します。
-
2レベル: パフォーマンスはシリアライズ・オブジェクト・ポリシーなしの場合よりほんのわずか向上します。
-
5レベル: パフォーマンスはシリアライズ・オブジェクト・ポリシーなしの場合より7倍向上します。
-
10レベル: パフォーマンスはシリアライズ・オブジェクト・ポリシーなしの場合より25倍向上します。
Exalogicでのシリアライズ・オブジェクト・ポリシーの使用の詳細は、「タスク2: Exalogicでのシリアライズ・オブジェクト・ポリシーの使用」を参照してください。
自動チューニング
自動チューニングは、特定の目的に対するJPAおよびセッション構成をアプリケーションが自動的にチューニングできるようにする最適化です。複数の構成オプションを単一のチューナで構成し、アプリケーション・デプロイメントの前後で、またセッションへの接続前にアプリケーションのメタデータが処理された後で、異なる構成を指定できます。自動チューニングにより、構成が簡単になり、動的な単一チューニング・オプションが使用可能になります。
チューナはorg.eclipse.persistence.tools.tuning.SessionTuner
インタフェースを実装することによって作成されます。2つのチューナ実装が用意されていて、必要に応じてカスタム・チューナを作成できます。
-
標準(
StandardTuner
): 標準チューナは、デフォルトで有効になっていて、デフォルトの構成設定を一切変更しません。 -
安全(
SafeModeTuner
): 安全チューナは、デバッグ用に永続ユニットを構成します。これは、キャッシュおよびいくつかのパフォーマンス最適化を無効にし、単純化したデバッグおよび開発構成を提供します。WEAVING_INTERNAL = false WEAVING_CHANGE_TRACKING = false CACHE_SHARED_DEFAULT = false JDBC_BIND_PARAMETERS = false ORM_SCHEMA_VALIDATION = true TEMPORAL_MUTABLE = true ORDER_UPDATES = true
チューナを有効にするには、事前定義済のチューナを指定するか、またはpersistence.xml
ファイルでSessionTuner
実装の完全修飾名をeclipselink.tuning
プロパティの値として入力します。次の例は、安全チューナを有効にします。
<property name="eclipselink.tuning" value="Safe"/>
tuning
プロパティの詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』を参照してください。
Exalogicの自動チューナの使用の詳細は、「タスク1: Exalogicの自動チューナの有効化」を参照してください。
EclipseLinkが有効なアプリケーションの監視および最適化
パフォーマンス・チューニングにおける最も重要な課題は、最適化の対象を知ることです。アプリケーションのパフォーマンスを向上させるには、アプリケーションの中で稼働時の効率が最大に達していない領域を特定します。この項では、次のことを説明します。
パフォーマンス最適化の推奨事項およびヒント
EclipseLinkには、アプリケーションのパフォーマンスを測定し、最適化するための様々な機能が用意されています。ほとんどの機能はディスクリプタまたはセッションで有効または無効にできるので、向上したパフォーマンスをグローバルに適用できます。開発サイクルのどの段階でもパフォーマンスを考慮する必要があります。これは、設計および実装作業の中でパフォーマンスの問題を認識していることを意味しますが、最初の試みで最高のパフォーマンスを達成する必要があるわけではありません。
たとえば、最適化によって設計が複雑になる場合は、最適化作業を最終的な開発フェーズに回します。それでも、後の統合が簡単になるように、最初の段階から最適化の計画を立てることは必要です。
EclipseLinkアプリケーションのチューニングに関連した最も重要な概念は、反復という考え方です。アプリケーションをチューニングする最も効果的な方法は、次のタスクを実行することです:
タスク1: EclipseLinkプロファイラを使用したEclipseLinkのパフォーマンスの測定
EclipseLinkパフォーマンス・プロファイラは、指定のセッション内で実行されたすべての問合せのパフォーマンス統計をロギングすることにより、パフォーマンスの問題を識別するために役立ちます。パフォーマンス・プロファイラを使用して、1つの問合せまたは単純なシングルスレッドのユースケースを監視します。
EclipseLinkパフォーマンス・プロファイラでは、次の情報がログ・ファイルに記録されます。
表18-1 EclipseLinkパフォーマンス・プロファイラでログに記録される情報
ログに記録される情報 | 説明 |
---|---|
問合せクラス |
問合せクラス名。 |
ドメイン・クラス |
ドメイン・クラス名。 |
合計時間 |
ネストされた問合せを含む、問合せの合計実行時間(ミリ秒)。 |
ローカル時間 |
ネストされた問合せを除く、問合せの実行時間(ミリ秒)。 |
オブジェクト数 |
影響を受けたオブジェクトの合計数。 |
1秒当たりのオブジェクト処理数 |
トランザクション時に一秒当たりに処理されたオブジェクト数。 |
ロギング |
ロギング・メッセージの出力に費やされた時間(ミリ秒)。 |
SQL準備 |
SQLスクリプトの準備に費やされた時間(ミリ秒)。 |
SQL実行 |
SQLスクリプトの実行に費やされた時間(ミリ秒)。 |
行フェッチ |
データベースからの行のフェッチに費やされた時間(ミリ秒) |
キャッシュ |
オブジェクト・キャッシュの検索または更新に費やされた時間(ミリ秒) |
オブジェクト・ビルド |
ドメイン・オブジェクトの作成に費やされた時間(ミリ秒) |
問合せ準備 |
実行する前に問合せの準備に費やされた時間(ミリ秒) |
SQL生成 |
SQLスクリプトをデータベースに送信する前にSQLスクリプトの生成に費やされた時間(ミリ秒) |
EclipseLinkプロファイラの有効化
EclipseLinkパフォーマンス・プロファイラは、org.eclipse.persistence.tools.profiler.PerformanceProfiler
クラスのインスタンスです。有効にするには、次の行をpersistence.xml
ファイルに追加します。
<property name="eclipselink.profiler" value="PerformanceProfiler.logProfiler"/>
EclipseLinkプロファイラの有効化に加えて、PerformanceProfiler
クラスのパブリックAPIでも、表18-2で説明する機能が提供されています。
表18-2 PerformanceProfilerの追加機能
目的 | 使用するもの |
---|---|
プロファイルを無効にします |
|
操作統計などの各操作プロファイルのすべてのサマリーに、プロファイラがログインするように編成します。操作統計にはプロファイリングされたすべての操作の最短時間、すべての操作の合計時間、プロファイリングされた問合せによって返されたオブジェクトの数、プロファイリングされた各種操作に要した合計時間などがあります。 |
|
プロファイラ・ログを、各操作プロファイルを問合せ別にまとめたサマリーとして編成します。 |
|
プロファイラ・ログを、各操作プロファイルをクラス別にまとめたサマリーとして編成します。 |
|
プロファイラの結果へのアクセスおよび解釈
プロファイリングの結果は、メモ帳などのテキスト・エディタでプロファイル・ログを開けば表示できます。
プロファイラ出力ファイルには、EclipseLinkが有効なアプリケーションのヘルスが示されます。
例18-7にEclipseLinkプロファイラの出力例を示します。
例18-7 パフォーマンス・プロファイラの出力
Begin Profile of{ ReadAllQuery(com.demos.employee.domain.Employee) Profile(ReadAllQuery,# of obj=12, time=139923809,sql execute=21723809, prepare=49523809, row fetch=39023809, time/obj=11623809,obj/sec=8) } End Profile
例18-7に、問合せに関する次の情報を示します。
-
ReadAllQuery(com.demos.employee.domain.Employee)
: プロファイリングした問合せとその引数 -
Profile(ReadAllQuery)
: プロファイルの開始と問合せのタイプ -
# of obj=12
: 問合せに関与したオブジェクトの数 -
time=139923809
: 問合せの合計実行時間(ミリ秒) -
sql execute=21723809
: SQL文の実行に要した合計時間 -
prepare=49523809
: SQL文の準備に要した合計時間 -
row fetch=39023809
: データベースからの行のフェッチに要した合計時間 -
time/obj=116123809
: 各オブジェクトで要した時間(ナノ秒) -
obj/sec=8
: 1秒当たりのオブジェクト処理数
タスク2: サーバー環境でのEclipseLinkのパフォーマンスの測定
パフォーマンス・モニターを使用して、マルチスレッド・サーバー環境で詳細なプロファイリングおよび監視情報を提供します。パフォーマンス・モニターを使用して、サーバー、複数のスレッドまたは長時間実行されているプロセスを監視します。
persistence.xml
ファイルで次のようにモニターを有効にします。
<property name="eclipselink.profiler" value="PerformanceMonitor"/>
パフォーマンス・モニターは、SessionCustomizer
を使用するコードを通じて有効にすることもできます。
パフォーマンス・モニターによって、累積統計のダンプが1分ごとにEclipseLinkログに出力されます。統計には、3つの情報セットが含まれます。
-
情報: セッション名やログイン時刻などの一定の情報データの統計です。
-
カウンタ: キャッシュ・ヒットや問合せ実行などの合計操作の累積カウンタの統計です。
-
タイマー: 特定のタイプの操作、読取り、書込み、データベース操作に対応する合計時間(ナノ秒)の累積測定の統計です。
統計は、通常、合計でグループ化されますが、問合せタイプ、問合せクラスおよび問合せ名によってもグループ化されます。カウンタとタイマーは、通常、同じ操作を対象に記録されるため、操作ごとの時間も計算可能です。
統計ダンプの間隔時間は、PerformanceMonitor
クラスのsetDumpTime(long)
メソッドを使用して構成できます。結果のダンプを行わない場合、dumpTime
属性をLong.MAX_VALUE
などの非常に大きな値に設定できます。統計には、getOperationTime(String)
メソッドを使用してJavaプログラムでアクセスすることもできます。
パフォーマンス・モニターは、プロファイルの重みで構成することもできます。プロファイルの重みは、SessionProfiler
クラスで定義され、PerformanceMonitorクラスによって使用されます。この重みには次のものが含まれます。
-
NONE
: 統計は記録されません。 -
NORMAL
: 情報統計が記録されます。 -
HEAVY
: 情報、カウンタおよびタイマー統計が記録されます。 -
ALL
: すべての統計が記録されます(これがデフォルトです)。注意:
現在のリリースでは、パフォーマンス・モニターは、
HEAVY
の値とALL
の値に対して同じ情報で応答します。
タスク3: フェッチ・グループ・フィールド使用状況の測定
フェッチ・グループ・モニターを使用して、フェッチ・グループのフィールド使用状況を測定します。これは、複雑なシステムでパフォーマンス分析を行う場合に便利です。
システム・プロパティのorg.eclipse.persistence.fetchgroupmonitor=true
を使用してこのモニターを有効にします。
新しい属性がアクセスされるたびに、モニターによって、クラスで使用される属性が出力されます。
タスク4: アプリケーションのパフォーマンス問題の原因特定
アプリケーションでパフォーマンスの問題が起こる可能性のある部分は、次のとおりです。
-
一般的なパフォーマンスの最適化の識別
-
スキーマ
-
マッピングおよびディスクリプタ
-
セッション
-
キャッシュ
-
データ・アクセス
-
問合せ
-
作業ユニット
-
アプリケーション・サーバーとデータベースの最適化
「タスク5: パフォーマンスが悪いアプリケーション・コンポーネントの変更」では、これらの各領域に対処するための簡単なガイドラインを説明します。
タスク5: パフォーマンスが悪いアプリケーション・コンポーネントの変更
「タスク4: アプリケーションのパフォーマンス問題の原因特定」に示されているアプリケーションのパフォーマンス問題の各原因に対して、この項で説明されている回避策を試みることができます。
一般的なパフォーマンスの最適化の識別
アプリケーションで必要な場合を除き、EclipseLinkのデフォルト動作をオーバーライドしないでください。これらの一部のデフォルトは、開発環境に適したものです(本番環境に合うようにするには、これらのデフォルトを変更します)。デフォルトは次などです。
-
バッチ書込み: 詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のjdbc.batch-writingに関する項を参照してください。
-
文のキャッシュ: 詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のjdbc.cache-statementsに関する項を参照してください。
-
接続プール・サイズの読み書き: 『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のconnection-poolに関する項を参照してください。
-
セッション・キャッシュのサイズ: 詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のmaintain-cacheに関する項を参照してください。
手動でコーディングするのではなく、ワークベンチを使用してください。これらのツールは使用しやすいだけでなく、デプロイXML(および必要に応じて生成されたコード)にエクスポートされるデフォルト構成は、ほとんどのアプリケーションに対して最適化されたベスト・プラクティスを示します。
スキーマ
データベース・スキーマおよびオブジェクト・モデルを設定する際には、最適化を考慮することが重要です。パフォーマンスの問題のほとんどは、オブジェクト・モデルやデータベース・スキーマが複雑すぎて、データベースが遅く、問合せが難しい場合に発生します。これが発生する可能性が高いのは、複雑なオブジェクト・モデルからデータベース・スキーマを直接導出した場合です。
パフォーマンスを最適化するには、オブジェクト・モデルとデータベース・スキーマを一緒に設計します。ただし、各モデルを最適に設計してください。これら2つが1対1に対応する必要はありません。
スキーマを最適化する方法には、次があります。
-
2つの表を1つに集約する
-
1つの表を多数に分割する
-
折りたたまれた階層を使用する
-
多数から1つを選択する
詳細は、『Oracle TopLinkの理解』のデータ・ストレージ・スキーマに関する項を参照してください。
マッピングおよびディスクリプタ
マッピングおよびディスクリプタにパフォーマンスのボトルネックが見つかった場合は、次の解決策を試みてください。
-
常にインダイレクション(遅延ロード)を使用します。インダイレクションは、最適化するデータベース・アクセスでクリティカルであるだけでなく、これによってキャッシュ・アクセスおよび作業ユニットの処理の最適化など、EclipseLinkでその他複数の最適化を実行できます。『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』のキャッシュの使用に関する項を参照してください。
-
EclipseLinkのマッピングで、特にgetメソッドまたはsetメソッドに負荷の高い、または副次的な危険性のあるコードが存在する場合は、メソッド・アクセスを使用しないようにし、かわりにデフォルトの属性への直接アクセスを使用してください。『Oracle TopLinkの理解』のメソッドまたは直接フィールド・アクセスの使用に関する項を参照してください。
-
アプリケーションで必要な場合以外は、存在チェック・オプションcheckCacheThenDatabaseをディスクリプタで使用しないようにします。デフォルトの存在チェック動作の方がパフォーマンスに優れています。『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@ExistenceCheckingに関する項を参照してください。
-
EclipseLinkがオブジェクトのインスタンス化に使用するデフォルト・コンストラクタで、初期化に高い負荷をかけないようにします。そのかわりに、遅延初期化またはEclipseLinkのインスタンス化ポリシーを使用してディスクリプタを構成し、別のコンストラクタを使用します。『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』の@InstantiationCopyPolicyに関する項を参照してください。
キャッシュ
キャッシュを使用すると、クラスタ環境でもキャッシュ・コーディネーションを実装することにより常にパフォーマンスを向上できます。キャッシュ・コーディネーションでは、分散される可能性のある複数のセッションのインスタンスが相互にオブジェクト変更を送信できるようになるので、各セッションのキャッシュは最新の状態を保つことができます。キャッシュの動作を最適化する方法の詳細は、『Oracle TopLinkの理解』のキャッシュに関する項および次の例を参照してください。
データ・アクセス
EclipseLinkでは、自分のアプリケーションからアクセスするデータ・ソースのタイプによって、低レベルのデータ読取りと書込みのパフォーマンス調整に使用できる、様々なLogin
オプションを提供します。高レベルのデータの読み書きを最適化するには、アプリケーションのデータ・アクセスのパフォーマンスを向上させるテクニックがいくつか記載されている、『Oracle TopLinkの理解』のデータ・アクセスに関する項を参照してください。そこでは、次の方法が説明されています。
-
JDBCドライバ・プロパティの最適化
-
データ形式の最適化。
-
バッチ書込みを使用した最適化
-
外部結合読取りと継承先サブクラスの使用
-
パラメータ化されたSQL(パラメータ・バインド)とプリコンパイルされたSQL文のキャッシュを使用した最適化
問合せ
EclipseLinkには、データの読取り、書込みおよび更新用の問合せにAPIが幅広く用意されています。アプリケーションの問合せのパフォーマンスを向上させるテクニックがいくつか記載されている、『Oracle TopLinkの理解』のEclipseLinkの問合せに関する項を参照してください。そこでは、次の方法が説明されています。
-
パラメータ化されたSQLとプリコンパイルされたSQL文のキャッシュを使用した最適化
-
名前付き問合せを使用した最適化
-
バッチ読取りと結合読取りを使用した最適化
-
部分オブジェクト問合せとフェッチ・グループを使用した最適化
-
読取り専用問合せを使用した最適化
-
JDBCフェッチ・サイズを使用した最適化
-
カーソル付きストリームとスクロール可能カーソルを使用した最適化
-
結果セットのページ区切りを使用した最適化
ここには、読取りおよび書込みの最適化の例へのリンクも示されています。
アプリケーション・サーバーとデータベースの最適化
アプリケーション・サーバーおよびデータベースのパフォーマンスを最適化するために、次の方法を検討してください。
-
アプリケーション・サーバーおよびデータベースを正しく構成すると、パフォーマンスおよびスケーラビリティに大きく影響する場合があります。EclipseLinkアプリケーションおよび永続性の他に、アプリケーションのこれらの主要コンポーネントを正しく最適化していることを確認してください。
-
アプリケーション・サーバーまたはJava EEサーバーの場合は、メモリー、スレッド・プール・サイズおよび接続プール・サイズが、サーバーで予測されるロードに十分であり、JVMの構成が最適であることを確認します。
-
最適なパフォーマンスと予測されるロードに対応できるように、データベースが正しく構成されていることを確認します。
タスク6: パフォーマンスの再測定
最後に、パフォーマンスのボトルネックになっている可能性のある場所を特定して、それらに対処した後、プロファイラを有効にしてアプリケーションを再実行します(「EclipseLinkプロファイラの有効化」を参照)。結果を検討し、さらに処置が必要な場合は、「タスク5: パフォーマンスが悪いアプリケーション・コンポーネントの変更」に示されている手順に従います。