Oracle® Fusion Middleware Oracle WebLogic Server JDBCアプリケーションの開発 12c (12.1.2) E48089-02 |
|
![]() 前 |
![]() 次 |
この章では、JDBCアプリケーションのパフォーマンスを向上させるために、WebLogic Serverを設計および構成する方法について説明します。
WebLogicには、JDBCアプリケーションのパフォーマンスを向上させるための機能がいくつか用意されています。
DBMSへのJDBC接続の確立には非常に時間がかかる場合があります。使用するアプリケーションでデータベース接続のオープンとクローズを繰り返す必要がある場合、これは重大なパフォーマンスの問題となります。WebLogicデータ・ソース内の接続プールを使用すると、こうした問題を効果的に解決できます。
WebLogic Serverを起動すると、データ・ソース内の接続が開き、すべてのクライアントで使用できるようになります。クライアントでデータ・ソースからの接続をクローズすると、その接続はプールに戻され、他のクライアントで使用できる状態になります。つまり、接続そのものはクローズされません。プールされた接続は、ほとんど負荷を生じることなくオープンしたりクローズしたりできます。
データベース・アプリケーションのパフォーマンスの良し悪しはほとんどの場合、アプリケーション言語ではなく、アプリケーションがどのように設計されているかによって決定されます。クライアントの数と場所、DBMS表および索引のサイズと構造、および問合せの数とタイプは、すべてアプリケーションのパフォーマンスに影響を与えます。
以下では、すべてのDBMSに当てはまる一般的なヒントを示します。また、アプリケーションで使用する特定のDBMSのドキュメントによく目を通しておくことも重要です。
DBMSアプリケーションのパフォーマンスに関する最も深刻な問題は、生データを不必要に移動することから発生します。これは、生データをネットワーク上で移動する場合にも、単にDBMSのキャッシュに出し入れする場合にも言えることです。こうした無駄を最小限に抑えるための良い方法は、クライアントがDBMSと同じマシンで動作している場合でも、ロジックをクライアントではなくデータの格納場所、つまりDBMSに置くことです。実際のところ、一部のDBMSでは、1個のCPUを共有するファット・クライアントとファットDBMSはパフォーマンスの致命的な低下をもたらします。
大部分のDBMSは、ストアド・プロシージャという、データの格納場所にロジックを置くための理想的なツールを備えています。ストアド・プロシージャを呼び出して10個の行を更新するクライアントと、同じ行を取得および変更し、UPDATE文を送信してその変更をDBMSに保存するクライアントの間には、パフォーマンスに大きな違いがあります。
また、DBMSのドキュメントを参照して、DBMS内のキャッシュ・メモリーの管理について調べる必要もあります。一部のDBMS (Sybaseなど)は、DBMSに割り当てられた仮想メモリーを分割し、特定のオブジェクトがキャッシュの固定領域を独占的に使用できるようにする機能を備えています。この機能を使用すると、重要な表または索引をディスクから一度読み出しておくことで、ディスクに再度アクセスしなくてもすべてのクライアントがそれらを使用できるようになります。
SQLは、セット処理言語です。DBMSは、完全にセット・ベース処理を行うように設計されています。データベースの1行へのアクセスは、例外なくセット・ベースの処理より遅く、またDBMSによっては実装が不完全です。たとえば、従業員100名に関するデータが格納されている4つの表がある場合、全従業員について各表を一度に更新する方が、従業員1名ごとに各表を100回更新するより常に高速です。
あまりに複雑すぎて1行ずつ処理する以外に方法がないと考えられていた処理の多くが、セット・ベースの処理に書き換えられ、パフォーマンスの向上を実現しています。たとえば、ある有名な給与管理アプリケーションは、巨大で低速なCOBOLアプリケーションから、連続実行される4つのストアド・プロシージャに変換されました。この結果、マルチCPUマシンで何時間もかかった処理が、より少ないリソースで15分で実行できるようになりました。
ユーザーからよく尋ねられる質問に、「特定の結果セットで返される行数はどのくらいか」というものがあります。すべての行を取り出さずに調べる唯一の方法は、次のようにcountキーワードを使用して同じ問合せを発行することです。
SELECT count(*) from myTable, yourTable where ...
これにより、関連するデータには変更がなかった場合に、オリジナルの問合せが戻すべき行数が返されます。また関連するデータに影響を与えるその他のDBMSアクティビティが起きた場合に、問合せを実行すれば、実際の行数は変わります。
ただし、これはリソースを大量に消費する処理であることに注意してください。元の問合せによっては、DBMSは行を送信するのと同じくらいの処理を行って行をカウントする必要があります。
アプリケーションの問合せは、実際にどのようなデータが必要なのかをできる限り具体的に指定する必要があります。たとえば、まず一時表に抽出し、カウントだけを返し、次に限定された2番目の問合せを送信して一時表内の行のサブセットだけを返すようにします。
クライアントが本当に必要なデータだけを抽出することが、きわめて重要です。ISAM (リレーショナル・データベース以前のアーキテクチャ)から移植された一部のアプリケーションでは、実際に必要なのは最初の数行だけであっても、表内のすべての行を選択する問合せが送信されます。また、最初に取得する行を得るために「sort by」句を使用するアプリケーションもあります。このようなデータベース問合せは、パフォーマンスを不必要に低下させます。
SQLを適切に使用すると、こうしたパフォーマンス上の問題を回避できます。たとえば、高額給与の社員のうち上位3人だけのデータが必要な場合、問合せを適切に行うには相関サブ問合せを使用します。表4-1に、次のSQL文で返される表全体を示します。
select * from payroll
相関サブ問合せ
select p.name, p.salary from payroll p where 3 >= (select count(*) from payroll pp where pp.salary >= p.salary);
表4-2に示すように、この問合せでは、より絞り込まれた結果が返されます。
この問合せでは、上位3名の高所得者の名前と給与が登録された3行だけが返されます。この問合せでは、給与表全体をスキャンし、次に各行について内部ループで給与表全体を再スキャンして、ループの外でスキャンした現在の行より高額の給与が何件あるかを調べます。この処理は複雑なように見えるかもしれませんが、DBMSはこの種の処理ではSQLを効率的に使用するように設計されています。
可能な限り、一連のデータ処理を収集し、更新トランザクションを次のような単一の文で発行してください。
BEGIN TRANSACTION UPDATE TABLE1... INSERT INTO TABLE2 DELETE TABLE3 COMMIT
この方法により、別個の文とコミットを使用するよりもパフォーマンスが向上します。バッチ内で条件ロジックと一時表を使用する場合でも、DBMSはさまざまな行と表に必要なすべてのロックを取得し、ワン・ステップで使用および解放するので、この方法は望ましいと言えます。別個の文とコミットを使用すると、クライアントとDBMS間の転送が増加し、DBMS内のロック時間が長くなります。こうしたロックにより、他のクライアントはそのデータにアクセスできなくなり、複数の更新がさまざまな順序で表を更新できるかによって、デッドロックが発生する可能性があります。
警告: 一意キー制約の違反などによって上記のトランザクション中の任意の文が適切に実行されなかった場合は、条件SQLロジックを追加して文の失敗を検出し、トランザクションをコミットせずにロールバックする必要があります。上の例の場合、INSERT文が失敗すると、ほとんどのDBMSは挿入の失敗を示すエラー・メッセージを返しますが、2番目と3番目の文の間でメッセージを取得したかのように動作して、コミットが行われてしまいます。Microsoft SQL Serverには、SQL set xact_abort on
の実行によって有効となる接続オプションがあります。このオプションを使用すると、文が失敗した場合にトランザクションが自動的にロールバックされます。
アプリケーションで、「BEGIN TRAN」
と、更新のために行または表をロックするSQLを送信する場合、ユーザーのキー入力がなければトランザクションをコミットできないようにアプリケーションを設計することは避けます。ユーザーがキー入力をせずに昼食に出かけてしまうと、ユーザーが戻ってくるまでDBMS全体がロックされてしまいます。
トランザクションの作成と完了にユーザー入力が必要な場合は、オプティミスティック・ロックを使用します。簡単に言えば、オプティミスティック・ロックでは問合せと更新でタイムスタンプとトリガーが使用されます。問合せは、トランザクション中にデータをロックすることなく、タイムスタンプ値を持つデータを選択し、そのデータに基づいてトランザクションを準備します。
更新トランザクションがユーザー入力によって定義されると、そのデータはタイムスタンプと共に単一の送信として送られます。これにより、そのデータが最初に取り出したデータと同じであることを確認できます。トランザクションが正常に実行されると、変更されたデータのタイム・スタンプが更新されます。別のユーザーからの更新トランザクションによって現在のトランザクションが処理するデータが変更された場合、タイム・スタンプが変更され、現在のトランザクションは拒否されます。ほとんどの場合、関連データが変更されることはないので通常トランザクションは正常に実行されます。あるトランザクションが失敗すると、アプリケーションは更新されたデータをもう一度フェッチして、必要に応じてトランザクションを再作成するよう通知します。
データ行の同位置での更新は、行の移動より非常に高速です。行の移動は、更新処理で表設計の許容範囲を超えるスペースが必要な場合に行う必要があります。必要なスペースを持つ行を最初から設計しておけば、更新は早くなります。ただし、表に必要なディスク空間は大きくなります。ディスク・スペースのコストは低いので、パフォーマンスが向上するのであれば、使用量を少しだけ増やすことは価値ある投資だと言えるでしょう。
アプリケーションによっては、操作データを履歴データと同じ表に格納するものもあります。時間の経過と共に履歴データが蓄積されていくと、すべての操作問合せでは、新しいデータを取得するために(日々の作業では)役に立たないデータを大量に読み取らなければなりません。これを回避するには、過去のデータを別の表に移動し、まれにしか発生しない履歴問合せのためにこれらの表を結合します。これを行うことができない場合、最も頻繁に使用されるデータが論理的および物理的に配置されるよう、表を索引処理およびクラスタリングします。
DBMSは、さまざまな作業を大量に処理するときに最も能力を発揮します。DBMSの最も不適切な使い方は、1つの大規模なシングル・スレッド・アプリケーション用のダム・ファイル・ストレージとして使用することです。容易に区別できる作業サブセットを扱う大量の並行処理をサポートするようアプリケーションとデータを設計すれば、そのアプリケーションはより高速になります。処理に複数のステップがある場合、先行ステップが完了するまで次のステップを待つのではなく、いずれかの先行ステップが処理を終えた部分のデータに対して後続ステップが処理を開始できるようにアプリケーションを設計します。これは常に可能であるとは限りませんが、このことに留意してプログラムを設計すると、パフォーマンスを大幅に向上させることができます。