プライマリ・コンテンツに移動
Oracle® Fusion Middleware Oracle Application Development FrameworkによるFusion Webアプリケーションの開発
12c (12.2.1.2.0)
E82918-03
目次へ移動
目次

前
次

9 ビュー・オブジェクトのパフォーマンス・チューニング

この章では、Oracle ADFアプリケーションでADFビュー・オブジェクトを設計および利用するときに使用できる高度な手法について説明します。

この章の内容は次のとおりです。

9.1 ビュー・オブジェクトのチューニングについて

JDeveloperには、ADFビジネス・コンポーネントのビュー・オブジェクトを構成したり、トランザクション時のパフォーマンスを向上させるためのツールが多数用意されています。

ビュー・オブジェクトを使用すると、データの行の読取り、一時的データの行の作成と格納、およびエンド・ユーザーが基礎のビジネス・オブジェクトに対して行う挿入、更新、削除の自動的な調整を行うことができます。ビュー・オブジェクトを設計および使用する方法が、実行時のパフォーマンスに影響を与える場合があります。ADFビジネス・コンポーネント用のJDeveloperデザインタイムには、最適なパフォーマンスを得るためのビュー・オブジェクトの構成に使用できる数多くの機能があります。

9.2 同じエンティティに基づくビュー・オブジェクトでの新しい行の一貫性の保持

ADFビジネス・コンポーネントでは、あるビュー・オブジェクト・インスタンスで作成した新しい行が、同じエンティティ・オブジェクトに基づいている他のビュー・オブジェクト・インスタンスに自動的に挿入されます。

1つのアプリケーション・モジュールで、エンティティ・ベースのビュー・オブジェクトの複数インスタンスが同じエンティティ・オブジェクトに基づいているときは、1つのインスタンスで作成された新しい行を、他のインスタンスの行セットに(再問合せを行うことなく)自動的に追加して、ユーザー・インタフェースの整合性を保つか、保留中のトランザクションの異なるアプリケーション・ページに新しい行を一貫して反映できます。顧客のオーダーのリストを表示するアプリケーションを考えてみます。顧客が新しいオーダーを作成する場合、このタスクは別のビュー・オブジェクトを介して実行され、カスタム・アプリケーション・モジュールのメソッドによって処理されます。このビュー・オブジェクトの新規行の整合機能を使用すると、新しく作成されたオーダーが、データベースに再度問い合せることなく、顧客の未処理オーダーのリストに自動的に表示されます。

歴史的な理由から、この機能はビュー・リンクの一貫性機能と呼ばれています。これは、Oracle Application Development Framework (Oracle ADF)の以前のリリースでは、アソシエーションに基づくビュー・リンクでの詳細ビュー・オブジェクト・インスタンスのサポートは、他の関連する行セットに対する新規行の追加にかぎられていたためです。現在では、このビュー・リンク一貫性機能は、ビュー・リンクに関連性があるかどうかには関係なく、この機能が有効になっているすべてのビュー・オブジェクトで機能します。

9.2.1 実行時に行われる処理: ビュー・リンクの一貫性が有効な場合

同じOrdersエンティティ・オブジェクトに基づく2つのエンティティ・ベースのビュー・オブジェクトOrdersViewSummaryOrdersViewについて考えます。一方のビュー・オブジェクト(OrdersViewなど)の行セットで新しい行が作成され、行の主キー行が設定されると、同じOrdersエンティティ・オブジェクトに基づくビュー・オブジェクト(OrdersViewSummaryなど)のの行セットは、新しい行が作成されたことを示すイベントを受け取ります。ビュー・リンク一貫性フラグが有効になっていると、新しい行のコピーの行セットへの挿入も行われます。

注意:

デフォルトでは、ビュー・リンク一貫性のメカニズムにより、新しい行は無条件に追加されます。関係するすべてのビュー・オブジェクトの行セットに新規行が追加されないようにする場合は、RowMatchオブジェクトにフィルタ式を記述して、行セットに追加される前に行を制限できます。詳細は、「行セットに追加されるポストされていない新規行を制限するためのRowMatchの使用方法」を参照してください。

9.2.2 ビュー・リンク一貫性のデフォルト設定の変更に関する必知事項

アプリケーション・モジュール構成(bc4j.xcfgファイル)の概要エディタで、jbo.viewlink.consistent構成パラメータを使用してビュー・リンク一貫性機能のデフォルト設定を制御できます。

アプリケーション・モジュール構成の概要エディタを表示するには、「アプリケーション」ウィンドウでアプリケーション・モジュールをダブルクリックして、概要エディタの「構成」ナビゲーション・タブを選択します。次に、概要エディタの「構成」ページで構成を選択し、構成のハイパーリンクをクリックします。アプリケーション・モジュール構成の概要エディタで「プロパティ」タブを選択し、「プロパティの追加」をクリックして「プロパティの追加」ダイアログからプロパティを選択し、「OK」をクリックします。

このパラメータのデフォルト設定はDEFAULTで、次のような意味があります。ビュー・オブジェクトが次の状態であるものとします。

  • 単一のエンティティ・オブジェクトの慣用名、ビュー・リンク一貫性は有効

  • 複数のエンティティ・オブジェクトの慣用名、かつ

    • すべてのセカンダリ・エンティティ・オブジェクトの慣用名が寄与する参照情報としてマークされている場合は、ビュー・リンク一貫性が有効

    • いずれかのセカンダリ・エンティティ・オブジェクトの慣用名が参照としてマークされていない場合は、ビュー・リンク一貫性が無効

この場合は、構成でjbo.viewlink.consistentに値falseを設定することで、この機能をグローバルに無効にできます。逆に、jbo.viewlink.consistentに値trueを設定するとこの機能をグローバルに有効にできますが、このように設定することはお薦めしません。有効に設定すると、現時点ではビュー・リンク一貫性機能がサポートされていない参照としてマークされていないセカンダリ・エンティティ・オブジェクトの慣用名を持つビュー・オブジェクトに対しても、強制的にビュー・リンク一貫性が設定されます。

この機能をプログラムで設定するには、任意のRowSetsetAssociationConsistent() APIを使用します。ビュー・オブジェクトでこのメソッドを呼び出すと、デフォルトの行セットに適用されます。

9.2.3 行セットに追加されるポストされていない新規行を制限するためのRowMatchの使用方法

ビュー・オブジェクトでビュー・リンク一貫性が有効になっている場合は、同じエンティティ・オブジェクトに基づく別のビュー・オブジェクトで作成された新しい行が、行セットに追加されます。デフォルトでは、新しい行は無条件に追加されます。ビュー・オブジェクトに、行の特定のサブセットのみを問い合せる設計時WHERE句がある場合は、ビュー・オブジェクトにRowMatchオブジェクトを適用して、同じフィルタ処理をメモリー内で実行できます。指定するRowMatchオブジェクトのフィルタ式により、そのオブジェクトに表示しても意味のない新規行は追加されません。

たとえば、OrdersByStatusビュー・オブジェクトには、次のような設計時WHERE句が含まれることがあります。

WHERE /* ... */ AND STATUS LIKE NVL(:StatusCode,'%') 

そのカスタムJavaクラスでは、create()メソッドが次の例に示すようにオーバーライドされており、ビュー・リンク一貫性を強制的に有効にします。また、Status属性が:StatusCode名前付きバインド変数の値と一致する行(または:StatusCode ='%'の場合はすべての行)に一致するフィルタ式を含むRowMatchオブジェクトを適用します。ビュー・リンク一貫性メカニズムは、このRowMatchフィルタを使用して、行セットに追加する候補の行を限定します。RowMatchで適格とされた行は追加されます。そうでない行は追加されません。

// In OrdersByStatusImpl.java
protected void create() {
  super.create();
  setAssociationConsistent(true);
  setRowMatch(new RowMatch("Status = :StatusCode or :StatusCode = '%'"));  
} 

RowMatchオブジェクトの作成と使用の詳細は、「RowMatchによるメモリー内フィルタ処理の実行」を参照してください。サポートされているSQL演算子のリストは、表10-2を参照してください。サポートされているSQL関数のリストは、表10-3を参照してください。

注意:

RowMatch機能では十分に制御できない場合は、ビュー・オブジェクトのrowQualifies()メソッドをオーバーライドして、カスタム・フィルタ処理ソリューションを実装できます。コードを使用して、新しい行をビュー・リンク一貫性メカニズムで追加するかどうかを決定できます。

9.2.4 動的なWHERE句とビュー・リンク一貫性に関する必知事項

ビュー・オブジェクトでsetWhereClause()を呼び出して動的WHERE句を設定すると、そのビュー・オブジェクトのビュー・リンク一貫性機能は無効になります。行セットに追加する新しい行を限定するために適切なカスタムRowMatchオブジェクトを提供していた場合は、setWhereClause()の後でsetAssociationConsistent(true)を呼び出すことで、ビュー・リンク一貫性を再び有効にできます。

行セットでビュー・リンク一貫性が有効になっている場合、他の行セットで作成されたために追加される新しい行は、行セットの最後に追加されます。

行セットでビュー・リンク一貫性が有効になっている場合、executeQuery()メソッドを呼び出すと、適格なポストされていない新規行は、問合せによってデータベースから取得された行が追加される前に、行セットの先頭に追加されます。

9.3 パラメータ付き問合せのためのバインド変数の使用方法

WHERE句の値が実行のたびに変化する可能性がある場合は、バインド変数を使用します。

問合せのWHERE句に実行のたびに変化する可能性のある値が含まれる場合は常に、名前付きバインド変数を使用する必要があります。ビュー・オブジェクトの概要エディタの「問合せ」ページで表示される「ビュー基準の作成」ダイアログを使用すると、そのようなタスクを簡単に実行できます。また、名前付きバインド変数を使用することで、悪質なエンド・ユーザーによるSQLインジェクション攻撃からアプリケーションを保護することもできます。バインド変数によるビュー基準の定義の詳細は、「名前付きビュー基準を宣言的に作成する方法」を参照してください。

9.3.1 問合せの再解析を防ぐためのバインド変数の使用

バインド変数は、SQL文字列内のプレースホルダであり、SQL文字列自体のテキストを変更することなく、実行時に簡単に値を変更できます。問合せのテキストは実行ごとに変化しないので、データベースは同じ解析済の文を毎回効率よく再利用できます。文の再解析を避けることで、データベースでは問合せ最適化プランを絶えず再決定する必要が軽減され、この解析操作の間に使用される他の貴重なデータベース・リソースに対する複数のエンド・ユーザーによる競合をなくすことができます。これらの減少により、実行時のアプリケーションのパフォーマンスが向上します。名前付きバインド変数の使用方法の詳細は、「ビュー・オブジェクト定義にWHERE句のバインド変数を追加する方法」を参照してください。

9.3.2 SQLインジェクション攻撃を避けるためのバインド変数の使用

パラメータを使用するWHERE句の値に対してバインド変数を使用することは、その値をアプリケーションのエンド・ユーザーが提供する場合に特に重要です。次に例を示します。この例は、ユーザーが指定したパラメータ値を文に連結して構成された動的なWHERE句を追加します。

// EXAMPLE OF BAD PRACTICE, Do not follow this approach!
String userSuppliedValue = ... ;
yourViewObject.setWhereClause("BANK_ACCOUNT_ID = "+userSuppliedValue);

悪質な意図を持つユーザーは、アプリケーションの基礎にあるデータベース・スキーマの詳細を知ることができれば、慎重に構成された銀行口座番号を、次のようにフィールド値またはURLパラメータとして提供できます。

BANK_ACCOUNT_ID

前述の例のコードで、動的に適用されるWHERE句にこの値を連結すると、データベースには次のような問合せ述語が示されます。

WHERE (BANK_ACCOUNT_ID = BANK_ACCOUNT_ID)

このWHERE句では現在のユーザーの口座だけでなくすべての銀行口座が取得され、ハッカーは他人の口座の個人情報を見ることができます。悪質な目的で作成されたパラメータ値をSQL文に提供することでアプリケーションのWHERE句を短絡するこのような手法のことを、SQLインジェクション攻撃と呼びます。このような場合は、かわりに次の例に示すように名前付きバインド変数を使用することで、脆弱性を回避できます。

// Best practice using named bind variables
String userSuppliedValue = ... ;
yourViewObject.setWhereClause("BANK_ACCOUNT_ID = :BankAcccountId");
yourViewObject.defineNamedWhereClauseParam("BankAcccountId", null, null);
yourViewObject.setNamedWhereClauseParam("BankAcccountId",userSuppliedValue);

この場合に悪質なユーザーが不正な値を提供すると、予想しないデータを取得するのではなく、アプリケーションが処理できるエラーを受け取ります。

9.3.3 バインド・パラメータ値のロギング

ビュー・オブジェクト問合せの実行に使用されるバインド・パラメータ値がわかるようにする必要がある場合は、テストの実行前またはデバッグ・セッション中に、ログ・レベルを構成できます。指定するログ・レベルによって、ログ・メッセージのタイプと量が決まります。バインド・パラメータの情報を表示するには、最低でもJavaログ・レベルCONFIGを設定する必要があります。ログ・アナライザの使用と構成の詳細は、「ログ・アナライザを使用してログ・メッセージを表示する方法」を参照してください。

また、ビュー・オブジェクトのViewObjectImplクラスのbindParametersForCollection()メソッドをオーバーライドすることにより、バインド・パラメータ値をプログラムでログに記録することもできます。このメソッドは、問合せで使用されるバインド・パラメータの名前と値をログに記録する場合に使用されます。これを実装してバインド・パラメータの値をログに記録できます。この機能は、バインド・パラメータがランタイムで生成されるようなシナリオで特に便利です。たとえば、ADF Facesツリー・コンポーネントがビュー・リンク・アソシエーションを使用して作成される場合、ノードにはバインド・パラメータで値が移入されますが、これをログに記録できます。次の例は、この目的でbindParametersForCollection()メソッドを定義する方法を示しています。

@Override protected void bindParametersForCollection(QueryCollection qc,
                                               Object[] params,
                                               PreparedStatement stmt) throws
SQLException {        String vrsiName = null;
        if (qc != null) {
            ViewRowSetImpl vrsi = qc.getRowSetImpl();
            vrsiName = vrsi.isDefaultRS() ? "<Default>" : vrsi.getName();
        }
        String voName = getName();
        String voDefName = getDefFullName();
        if (qc != null) {
            System.out.println("----[Exec query for VO=" + voName + ", RS=" + 
                               vrsiName + "]----");
        } else {
            System.out.println("----[Exec COUNT query for VO=" + voName + 
                               "]----");
        }
        System.out.println("VODef =" + voDefName);
        System.out.println(getQuery());
        if (params != null) {
            if (getBindingStyle() == SQLBuilder.BINDING_STYLE_ORACLE_NAME) {
                StringBuilder binds = new StringBuilder("BindVars:(");
                int paramNum = 0;
                for (Object param : params) {
                    paramNum++;
                    Object[] nameValue = (Object[])param;
                    String name = (String)nameValue[0];
                    Object value = nameValue[1];
                    if (paramNum > 1) {
                        binds.append(",");
                    }
                    binds.append(name).append("=").append(value);
                }
                binds.append(")");
                System.out.println(binds);
            }
        }
        super.bindParametersForCollection(qc, params, stmt);
    

9.4 複数の行セットと行セット・イテレータの使用

JDeveloperでは、名前付きのセカンダリ行セットおよび名前付きのセカンダリ行セット・イテレータを作成できます。

通常はビュー・オブジェクトのデフォルトの行セットを使用しますが、ViewObjectインタフェースのcreateRowSet()メソッドを呼び出して、同じビュー・オブジェクトの問合せに基づく行セットである、二次的な名前付きの行セットを作成できます。こうすることに意味のある状況の1つは、ビュー・オブジェクトのSQL問合せに名前付きバインド変数が含まれる場合です。各RowSetオブジェクトはバインド変数値の独自のコピーを格納するので、単一のビュー・オブジェクトを使用して、異なる組合せのバインド変数値に基づく複数の行セットを生成および処理できます。作成した名前付き行セットは、findRowSet()メソッドを使用して検索できます。セカンダリ行セットの使用が終了したら、closeRowSet()メソッドを呼び出します。

RowSetに対し、通常はデフォルトの行セット・イテレータを使用しますが、RowSetインタフェースのcreateRowSetIterator()メソッドを呼び出して、二次的な名前付きの行セット・イテレータを作成できます。作成した名前付き行セット・イテレータは、findRowSetIterator()メソッドを使用して検索できます。セカンダリ行セット・イテレータの使用が終了したら、closeRowSetIterator()メソッドを呼び出します。

パフォーマンスに関するヒント:

結果セットに対してプログラム的に反復を実行する必要があるとき、デフォルトの行セット・イテレータの現在行が妨害されることを避けるために、セカンダリ・イテレータを作成します。たとえば、ADF Modelの宣言的データ・バインディング・レイヤーを通して、アプリケーションのユーザー・インタフェース・ページは、アプリケーション・モジュールのデータ・モデル内にあるビュー・オブジェクトのデフォルト行セットのデフォルト行セット・イテレータと連携します。このシナリオでは、ビュー・オブジェクトのデフォルト行セットに対して反復処理を行うビジネス・ロジックを担当する行セットのセカンダリ・イテレータを作成しない場合、結果的にユーザー・インタフェース・レイヤーによって使用されるデフォルトの行セット・イテレータの現在行が変更されます。

9.5 読取り専用データへのエンティティ・ベースのビュー・オブジェクトの使用方法

機能要件に応じて、JDeveloperでは、読取り専用のビュー・オブジェクトを設計できます。このようなビュー・オブジェクトは、SQL検証や選択コンポーネントでの値リストの表示などに使用します。

一般に、SQLベースの検証のため、およびドロップダウン・リストに有効な選択肢のリストを表示するために使用されるビュー・オブジェクトは、読取り専用でかまいません。アプリケーションに必要な機能の種類を判断し、それに応じてビュー・オブジェクトを設計する必要があります。

ベスト・プラクティス:

以前のリリースでは、読取り専用データに関するベスト・プラクティスとして、読取り専用のカスタムSQLビュー・オブジェクトを作成することが推奨されていました。この推奨の意図は、エンティティ・オブジェクト・キャッシュに関連する行を格納するオーバーヘッドを回避することでした。現在は、このベスト・プラクティスを考慮する必要のない、最適化された対処法があります。

現在のリリースの場合、データを参照するために読取り専用ビュー・オブジェクトを作成する必要があるときは、エンティティ・ベースのビュー・オブジェクトを使用し、ビュー・オブジェクトの概要エディタの「エンティティ・オブジェクト」ページで「更新可能」オプションの選択を解除してください。この手法には、2つの利点があります。第一は、SQL問合せの生成に役立つ設計時エディタを利用できることであり、第二は、ビュー・オブジェクトを更新可能にすることにした場合に、すでに更新可能なエンティティ・オブジェクトがその基礎となっていることです。

読取り専用のカスタムSQLビュー・オブジェクトを作成するという、これに替わる方法にも、本格的なSQL問合せを指定できるという利点があり、エンティティ・オブジェクトの使用ではユニオンやグループ化を表現できないような場合に、特に役立ちます。

ビュー・オブジェクトは、基礎になっているエンティティ・オブジェクトに関連付けることも、関連付けないこともできます。ビュー・オブジェクトが基礎になっているエンティティ・オブジェクトと関連付けられていると、デフォルト動作で新しい行の作成、および問合せで得られた行の変更や削除がサポートされます。ただし、更新機能は、エンティティ・ベースのビュー・オブジェクトの概要エディタで「更新可能」の選択を解除して無効にできます(図9-1を参照)。

図9-1 エンティティ・ベースのビュー・オブジェクトでの「更新可能」オプションの選択の解除

この図は周囲のテキストで説明しています

かわりの方法として、読取り専用ビュー・オブジェクトを作成し、概要エディタの「問合せ」ページで「カスタムSQLの書込み」を選択して、SQL問合せを定義することもできます。エディタによって問合せ作成作業が簡素化されるため、複雑なSQL文の構築に慣れていないビジネス・コンポーネント開発者にとっては、エンティティ・オブジェクトに基づいて更新不可のビュー・オブジェクトを作成する方が、常に便利です。更新不可に設定したエンティティ・ベースのビュー・オブジェクトは、読取り専用のカスタムSQLビュー・オブジェクトと比べて、次の点で有利です。

  • ユーザー・インタフェースに必要とされる属性のみが含まれるように、実行時に選択リストを最適化できます。

  • エンティティ・オブジェクトを使用したローカル・キャッシュの作成による、大幅なパフォーマンスの劣化はありません。

  • ビュー・オブジェクト内のデータは、読取り操作ごとにデータベースに戻す必要はなく、むしろローカル・キャッシュの状態を表します。

  • 定義した別のビュー・オブジェクトで更新不可のビュー・オブジェクトのベース・エンティティ・オブジェクトの更新が必要になっても、ローカル・キャッシュ内のデータは一貫性を維持します。

このため、ビュー・オブジェクト行とエンティティ・オブジェクト行の間の調整には、実行時に若干のオーバーヘッド(概算では5%未満のオーバーヘッド)が生じますが、ビュー・オブジェクト定義を完全に宣言的に維持し、カスタマイズ可能なビュー・オブジェクトをメンテナンスする機能と比較検討してください。カスタムSQLビュー・オブジェクトはカスタマイズ不可ですが、エンティティ・オブジェクトでは表現できないUNIONおよびGROUP BY問合せの実行に使用できます。カスタムSQLビュー・オブジェクトは、ビュー・オブジェクト・ベースのキー存在バリデータによって使用されるSQLベースの検証問合せでも便利です。

データが読取り専用でないとき、最善の(そして唯一の)選択肢はエンティティ・ベースのビュー・オブジェクトを作成することです。更新可能(デフォルト動作)なエンティティ・ベースのビュー・オブジェクトは、エンティティから導出される属性のデフォルト値の取得、同じトランザクション内の他のビュー・オブジェクトを介して関連エンティティ・オブジェクトに行われた保留中の変更の反映、およびエンティティ・ベースのビュー・オブジェクトを使用するために外部キー属性値が変更されたときに更新された参照情報の反映の唯一の方法です。

9.6 異常な問合せを識別するためのSQLトレースの使用方法

JDeveloperでは、データベース問合せオプティマイザで使用される問合せ計画が全表スキャンを実行してパフォーマンス・オーバーヘッドが生じないように問合せをチューニングできます。

ビュー・オブジェクトをエンティティにマップするかどうかを決定した後は、次に問合せ自体に注目します。ビュー・オブジェクトの概要エディタの「問合せ」ページで、「テストおよび説明」ボタンをクリックし、データベースの問合せオプティマイザで使用される問合せ計画を表示します。計画が全表スキャンを行っている場合は、索引を追加するか、または概要エディタの「一般」ページの「チューニング」セクションで、「問合せオプティマイザ・ヒント」フィールドの値を指定することを検討する必要があります。これにより、使用される問合せ計画を明示的に制御できます。これらの機能は、個別のビュー・オブジェクトSQL文について問合せ計画を評価するための便利なツールを開発者に提供します。ただし、これらのツールの使用は、本番環境のデータ量とエンド・ユーザー数においてパフォーマンスの悪い問合せを識別するための、アプリケーション全体のSQLのトレースにかわるものではありません。

OracleデータベースのSQLトレース機能を使用すると、アプリケーションが実行する全SQL文の完全なログが生成されます。すべてのバージョンのOracleデータベースで動作する方法としては、次のコマンドを発行します。

ALTER SESSION SET SQL_TRACE TRUE

特にOracle 10gでは、このコマンドを実行するために、DBAはALTER SESSION権限を付与する必要があります。

このコマンドを実行すると、現在のデータベース・セッションのトレースが有効になり、ALTER SESSION SET SQL_TRACE FALSEを入力するまで、または接続を閉じるまで、すべてのSQL文がサーバー側のトレース・ファイルに記録されます。このオプションの有効化を簡単にしてFusion Webアプリケーションをトレースするには、次の例に示すように、アプリケーション・モジュール(またはカスタム・アプリケーション・モジュール・フレームワーク拡張クラス)のafterConnect()メソッドをオーバーライドし、Javaシステム・プロパティが存在するかどうかに基づいて、条件付きでALTER SESSIONコマンドを実行してSQLトレースを有効にします。

// In YourCustomApplicationModuleImpl.java
protected void afterConnect() {
  super.afterConnect();
  if (System.getProperty("enableTrace") != null) {
    getDBTransaction().executeCommand("ALTER SESSION SET SQL_TRACE TRUE");
  }
}  

トレース・ファイルを生成した後は、データベースに付属するTKPROFユーティリティを使用して情報を書式設定することで、次のように実行された各問合せに関する情報を理解しやすくなります。

  • (再)解析された回数

  • 実行された回数

  • アプリケーション・サーバーとデータベースの間で行われたラウンドトリップの回数

  • 問合せの実行時間に関する様々な定量的測定値

これらの手法を使用することで、アプリケーションが実行する特定の問合せの時間を短縮するために必要な追加索引や、問合せ最適化計画を改善するために変更できる問合せを判断できます。TKPROFユーティリティでの作業の詳細は、「アプリケーション・トレースの実行」、SQLトレースとTKPROFの理解に関する項およびSQLトレース機能とTKPROFの使用に関する項を参照してください。

注意:

Oracleデータベースが提供するDBMS_MONITORパッケージでは、SQLトレースがさらに簡単になっており、Oracle Enterprise Managerと統合してアプリケーションが最も頻繁に実行する問合せ文を視覚的にモニタリングできます。

9.7 適切なビュー・オブジェクト・チューニング設定の使用方法

ビュー・オブジェクトの概要エディタの「チューニング」セクションには、問合せパフォーマンスをチューニングするための様々なオプションが用意されています。

ビュー・オブジェクトの概要エディタの「一般」ページの「チューニング」セクションでは、問合せのパフォーマンスに劇的な影響を与える可能性のある様々なオプションを設定できます。図9-2に、新しいビュー・オブジェクトで定義されているデフォルトのオプションを示します。

図9-2 ビュー・オブジェクトのデフォルト・チューニング・オプション

この図は周囲のテキストで説明しています

9.7.1 「データベースから取得」オプションに関する必知事項

ビュー・オブジェクトの概要エディタの「一般」ページにある、「データベースから取得」グループ・ボックスは、ビュー・オブジェクトがデータベース・サーバーから行を取得する方法を制御します。フェッチ・モードのオプションは、「すべての行」「行番号までのみ」、「最大で1行」および「行なし」です。ほとんどのビュー・オブジェクトはデフォルトの「すべての行」オプションを使用し、「必要に応じて」(デフォルト)または「一度にすべて」のいずれか選択されているオプションに従って取得されます。

注意:

「同時」オプションでは、ビュー・オブジェクト問合せで指定された行をフェッチするためのデータベース・ラウンドトリップを一切強制しません。「必要に応じて」および「同時」オプションは、「バッチ」(フェッチ・サイズとも呼ばれます)の値と連携して、ラウンドトリップ数を決定します。データベース・アクセスのパフォーマンスを最高に保つには、「一度に1行のフェッチが適切かどうかの検討」の説明に従ってフェッチ・サイズを変更することを検討してください。

「必要に応じて」オプションを指定すると、ビュー・オブジェクトでのexecuteQuery()操作は最初に、表示する最初のページに必要な数の行のみを取得します。この行数は、ビュー・オブジェクトの範囲サイズに基づいて設定されます。「必要に応じて」を使用する場合、最初の範囲サイズ(「レンジ・サイズ」オプションで定義される)で指定された行数を取得するために必要な回数だけ、データベース・ラウンドトリップが要求されます。「同時」を使用する場合、アプリケーションでは、「バッチ」(フェッチ・サイズ)の値と問合せによって識別された行数に基づいて、すべての行を取得するために必要な回数のラウンドトリップが実行されます。

WHERE句が単一の行を取得すると予想されるビュー・オブジェクトの場合は、オプションを「最大で1行」に設定すると最良のパフォーマンスが得られます。このオプションを指定すると、ビュー・オブジェクトはユーザーがそれ以上の行を期待していないことを認識し、さらに行がある場合に通常行うテストをスキップします。最後に、ビュー・オブジェクトを新規行の作成のみを目的として使用する場合は、最適なパフォーマンスを得るために、このオプションを「行なし」に設定すると、問合せは実行されなくなります。

始める前に:

ビュー・オブジェクトに関する知識が役立つ場合があります。詳細は、「ビュー・オブジェクトについて」を参照してください。

行オブジェクトの行フェッチ・オプションを設定するには:

  1. 「アプリケーション」ウィンドウで、編集するビュー・オブジェクトをダブルクリックします。

  2. 概要エディタで、「一般」ナビゲーション・タブをクリックし、「チューニング」セクションを開きます。

  3. 「データベースから取得」グループ・ボックスで、データベースからフェッチする行数を制御するオプションを選択します。

  4. ビュー・オブジェクトの問合せを最適化するためにデータベースで使用される、「問合せオプティマイザ・ヒント」を入力します。

    実行時、このヒントは問合せのSELECTキーワードの直後に追加されます。たとえば、すべての行をできるだけ迅速に取得する必要がある場合は、ALL_ROWSと入力します。また、(すべての行の取得を最適化しないで)最初の行をできるだけ迅速に取得する場合は、FIRST_ROWSと入力します。

9.7.2 一度に1行のフェッチが適切かどうかの検討

フェッチ・サイズは、データベースへの各ラウンドトリップで返される行数を制御します。デフォルトでは、フレームワークは一度に1行のバッチで行をフェッチします。複数の行をフェッチする場合、ビュー・オブジェクト概要エディタの「一般」ページの「チューニング」セクションにあるこの「次の単位で」の値を設定して効率を上げます。

本当に1行のみフェッチするのでないかぎり、「次の単位で」フィールドをデフォルトのフェッチ・サイズである1のままにしておくことはお薦めしません。これは、アプリケーション・サーバーとデータベースの間で必要以上に多くのラウンドトリップが発生するためです。各ビュー・オブジェクトのフェッチ・サイズに適した値を検討することを強くお薦めします。

ユーザー・インタフェースで一度にn行の結果を表示する場合は、簡単なWebページでは、データベースへの1回のラウンドトリップで各ページの結果を取得できるよう、フェッチ・サイズを少なくともn+3に設定するのがよい方法です。ただし、この値を大きくすると、クライアント側で必要なバッファが大きくなるため、この数を、Oracle JDBCフェッチ・サイズの推奨を超える値に設定しないでください。

通常、フェッチ・サイズはOracleデータベース12cの推奨事項と一致している必要があります。つまり、フェッチ・サイズが100程度であっても、場合によってはそれよりも大きなサイズが適切になります。詳細は、Oracle Database 12c『Oracle JDBC Memory Management』(http://www.oracle.com/technetwork/database/application-development/jdbc-memory-management-12c-1964666.pdf)を参照してください。

始める前に:

ビュー・オブジェクトに関する知識が役立つ場合があります。詳細は、「ビュー・オブジェクトについて」を参照してください。

ビュー・オブジェクトのデータベース・ラウンドトリップ数を制限するには:

  1. 「アプリケーション」ウィンドウで、編集するビュー・オブジェクトをダブルクリックします。

  2. 概要エディタで、「一般」ナビゲーション・タブをクリックし、「チューニング」セクションを開きます。

  3. 「データベースから取得」グループ・ボックスで、「すべての行」または「行番号までのみ」を選択します。

  4. 「次の単位で」フィールドに、各データベース・ラウンドトリップで返す行数を入力します。

  5. フェッチされた行数が行セットを表示するWebページに収まるかどうかに関係なく、すべての行をフェッチする場合は、オプション「一度にすべて」を選択します。そうではなく、行セットを表示するWebページの最初のページを埋めるために必要な行数のみをフェッチする場合は、デフォルト設定である「必要に応じて」のままにします。

    「一度にすべて」を選択する場合、アプリケーションでは、「次の単位で」(フェッチ・サイズ)の値と問合せによって特定された行数に基づいて、すべての行を取得するために必要な回数のラウンドトリップが実行されます。

9.7.3 必要に応じた問合せオプティマイザ・ヒントの指定

「問合せオプティマイザ・ヒント」フィールドでは、Oracle問合せオプティマイザに対するオプションのヒントを指定して、使用される実行計画に影響を与えることができます。図9-2に示すように、このヒントは、ビュー・オブジェクトの概要エディタの「チューニング」ページで設定することができます。

実行時には、指定したヒントが問合せのSELECTキーワードの直後に追加され、特殊なコマンド構文/*+ YOUR_HINT */でラップされます。一般的な2つのオプティマイザ・ヒントを次に示します。

  • FIRST_ROWS - できるかぎり早く最初の行を取得することを示します。

  • ALL_ROWS - できるかぎり早くすべての行を取得することを示します。

他にも多くのオプティマイザ・ヒントがありますが、このマニュアルの範囲からは外れます。使用できるヒントの詳細は、Oracleのデータベース・リファレンス・マニュアルを参照してください。

始める前に:

ビュー・オブジェクトに関する知識が役立つ場合があります。詳細は、「ビュー・オブジェクトについて」を参照してください。

ビュー・オブジェクト定義を編集するには:

  1. 「アプリケーション」ウィンドウで、編集するビュー・オブジェクトをダブルクリックします。

  2. 概要エディタで、「一般」ナビゲーション・タブをクリックし、「チューニング」セクションを開きます。

  3. 「データベースから取得」グループ・ボックスで、データベースからフェッチする行数を制御するオプションを選択します。

  4. ビュー・オブジェクトの問合せを最適化するためにデータベースで使用される、「問合せオプティマイザ・ヒント」を入力します。

    実行時、このヒントは問合せのSELECTキーワードの直後に追加されます。たとえば、すべての行をできるだけ迅速に取得する必要がある場合は、ALL_ROWSと入力します。また、(すべての行の取得を最適化しないで)最初の行をできるだけ迅速に取得する場合は、FIRST_ROWSと入力します。

9.8 ビュー・オブジェクトの最大フェッチ・レコード数を制限するためのフェッチ・サイズの使用方法

ビュー・オブジェクトで取得される行数に上限を設定できます。すべてのビュー・オブジェクト問合せに対するグローバルしきい値を構成することも、特定のADFビュー・オブジェクト問合せに対するしきい値を構成することもできます。

アプリケーションでビュー・オブジェクトの問合せ結果行を反復処理する必要がある場合は、フェッチするレコードの最大数を指定することをお薦めします。ビュー・オブジェクトのデフォルトの最大フェッチ・サイズは-1で、フェッチできる行数に制限がないことを示します。デフォルトでは、行は必要に応じてフェッチされるので、-1という値はビュー・オブジェクトがすべての行をフェッチする必要があることを意味するわけではありません。問合せ結果のすべての行を反復処理しようとした場合に、すべての行が取得されることを意味しているにすぎません。

ビュー・オブジェクトで取得される行の最大数に上限を設けるには、次の設定を使用します。

  • adf-config.xmlファイルの概要エディタの「ビジネス・コンポーネント」ページで、「行フェッチ制限」プロパティを使用して、すべてのビュー・オブジェクト問合せのグローバルしきい値を構成できます。このファイルは、「アプリケーション・リソース」パネルで「ディスクリプタ」および「ADF META-INF」ノードを開いて特定できます。

    注意: 行フェッチ制限ではそのアプリケーションのすべての問合せ操作のグローバルしきい値が指定されるため(イテレータ結果セットの予測行カウントを決定するイテレータ・バインディング・プロパティRowCountThresholdを含む)、このプロパティを使用すると、その操作のデフォルト動作ではすべての行をフェッチできる場合に、個々の問合せ操作の設定を変更しなくて済みます。個々のビュー・オブジェクトに「最大フェッチ・サイズ」を使用してフェッチ制限を指定する場合、「行フェッチ制限」の設定は無視されます。ビュー・オブジェクトに適した値を返すようにビュー・オブジェクトの実装クラスでgetRowLimit()をオーバーライドする場合は、「行フェッチ制限」の設定も無視されます。

  • ビュー・オブジェクトの概要エディタの「一般」ページにある「チューニング」セクションで、「行番号までのみ」フィールドを選択すると、特定のビュー・オブジェクト問合せのしきい値を構成できます。プロパティ・インスペクタでは、この設定が「最大フェッチ・サイズ」プロパティに表示されることに注意してください。

ヒント:

「行フェッチ制限」を使用して問合せ操作のグローバルしきい値を設定する際、特定のビュー・オブジェクト問合せで使用可能なすべての行が戻されるようにする場合は、該当するビュー・オブジェクトの「行番号までのみ」フィールドを非常に大きい数値にして「最大フェッチ・サイズ」を設定できます。

たとえば、ORDER BY句を含む問合せを作成し、ページに上位N項目を表示するために最初のn行を返す場合は、ビュー・オブジェクトの概要エディタを使用して、「一般」ページの「チューニング」セクションにある「行番号までのみ」フィールドの値を指定できます。たとえば、最初の5行のみをフェッチするには、このフィールドに5を入力します。これは、ビュー・オブジェクトでsetMaxFetchSize()メソッドをコールして最大フェッチ・サイズを5に設定するのと同じです。ビュー・オブジェクトは、最大フェッチ・サイズに達すると行のフェッチを停止します。通常は、この手法と組み合せて、概要エディタの「一般」ページの「チューニング」セクションで、FIRST_ROWS「問合せオプティマイザ・ヒント」も指定します。これにより、すべての行の取得の最適化を試みるのではなく、できるかぎり早く最初の何行かを取得するよう、データベースにヒントが提供されます。

9.9 範囲サイズを使用したページ単位でのデータの提示およびスクロール

各ページで既定数のデータ行を取得して管理するように、ADFビュー・オブジェクトを構成できます。

1ページずつデータを提示およびスクロールするために、適切なサイズの行範囲がビュー・オブジェクトで管理されるように構成できます。範囲機能を使用すると、クライアントは、行セット内の行のサブセットを簡単に表示および更新でき、一度にn行ずつ簡単に後のページにスクロールできます。1ページに表示するデータの行数を定義するには、setRangeSize()を呼び出します。デフォルトの範囲サイズは1行です。-1という範囲サイズは、範囲が行セットのすべての行を含むことを示します。

注意:

ADFモデル・レイヤーの宣言的バインディングを使用する場合、ページ定義ファイルイテレータ・バインディングRangeSize属性があります。実行時に、イテレータ・バインディングは対応する行セット・イテレータsetRangeSize()メソッドを呼び出し、このRangeSize属性の値を渡します。ADFの設計時には、デフォルトで、ほとんどのイテレータ・バインディングについて、RangeSize属性に10行が設定されます。例外は、ドロップダウン・リストなどのUIコンポーネントに対する有効値の設定を提供するリスト・バインディングに指定される範囲サイズです。この場合は、デフォルトの範囲サイズは-1であり、範囲は行セットのすべての行を含むことができます。

1より大きい範囲サイズを設定するときは、イテレータ・モードを使用して行セットのページ移動動作を制御します。次の2つのイテレータ・モード・フラグを、setIterMode()メソッドに渡すことができます。

  • RowIterator.ITER_MODE_LAST_PAGE_PARTIAL

    このモードでは、最終ページに含まれる行数は、範囲サイズより少なくてもかまいません。たとえば、範囲サイズを10に設定し、行セットに23行が含まれる場合は、3ページ目には3行のみ含まれます。これは、Fusion Webアプリケーションに対して最善のスタイルです。

  • RowIterator.ITER_MODE_LAST_PAGE_FULL

    このモードでは、最終ページにも1ページ分の行数が表示され、前のページの下部に表示されていた行が、最後のページの上部に表示される場合があります。たとえば、範囲サイズを10に設定し、行セットに23行が含まれる場合は、3ページ目にも10行が表示され、3ページ目の最初から7行には、2ページ目の最後の7行が表示されます。これは、Swingを使用するデスクトップ・フィデリティ・アプリケーションに最適なスタイルです。

9.10 大きい結果セットを効率的にスクロールするための範囲ページ移動の使用方法

Fusion Webアプリケーションでは、問合せでフェッチされるADFビジネス・コンポーネントの行数をあらかじめ決定することで、規模が非常に大きい問合せ結果を制限できます。非常に規模が大きい場合は、さらにフィルタ基準を指定するようにエンド・ユーザーにプロンプトを表示できます。

一般的な規則として、パフォーマンスを最高にするため、非常に大きな問合せ結果をエンド・ユーザーがスクロールすることがないような方法でアプリケーションを作成することをお薦めします。この推奨事項を実現するには、実際に問合せを実行してユーザーが操作を継続できるようにするに、ビュー・オブジェクトでgetEstimatedRowCount()メソッドを呼び出して、ユーザーの問合せで返される行数を判定します。推定される行カウントが不当に大きい場合は、さらに検索基準を提供するようエンド・ユーザーに要求できます。

ただし、非常に大きな結果セット(通常、100行超)を処理する必要がある場合は、範囲ページ移動と呼ばれるビュー・オブジェクトのアクセス・モードを使用して、パフォーマンスを向上することができます。この機能を使用すると、大きなデータ・セットについてデフォルトのスクロール可能アクセス・モードより効率的な方法で、一度にある行範囲のページ単位で、前方および後方にデータを移動できます。

範囲ページ移動アクセス・モードは、通常、読取り専用行セットのページ移動に使用され、読取り専用ビュー・オブジェクトで使用されるのが普通です。ユーザーは範囲ページ移動アクセス・モードを使用し、大きな行セットをページ移動して対象行を検出できます。その後、その行のKeyを使用し、編集用に別のビュー・オブジェクトで選択されている行を検索できます。

ビュー・オブジェクトの場合の範囲ページ移動は、標準アクセス・モードと、範囲ページ移動と結果セット・スクロールの利点を組み合せてデータベース・アクセス回数を最小限に抑える標準アクセス・モードのバリエーションをサポートしています。次に、ビュー・オブジェクト範囲ページ移動機能のこれらのモードについて説明します。

  • RANGE_PAGING: 標準アクセス・モードで、範囲サイズで指定された行数をフェッチします。このモードでは、データベースに再問合せを行わずにスクロールできる行数は、設定した範囲サイズで決まります。デフォルトでは1行をフェッチしますが、範囲サイズは、ユーザーが次の結果セットまでスクロールせずに表示できる行数と同じ数に設定するものと想定されています。エンド・ユーザーが範囲外の行にアクセスするたびに、アプリケーションはデータベースに再問合せを行います。このため、行セットを前後にスクロールすると、データベースに再問合せが行われます。このデータベース中心のページ移動方針の説明は、「上位N問合せのサポート方法の理解」を参照してください。

  • RANGE_PAGING_INCR: インクリメンタル・アクセス・モードを使用して、一度に表示できる行数をUI設計者がより柔軟に決定でき、データベース問合せ回数も最小限に抑えます。このモードでは、UIは結果セットをメモリー・キャッシュから逐次表示するため、スクロールは1回のデータベース問合せの範囲内でサポートします。エンド・ユーザーが1回の問合せでスクロールできる行数は、範囲サイズと、設定した範囲ページ移動キャッシュ・ファクタによって決まります。たとえば、範囲サイズを4、キャッシュ・ファクタを5に設定したとします。この場合、メモリーにキャッシュする最大行数は、4*5 = 20です。キャッシュの動作の詳細は、「範囲ページ移動を使用するときのビュー行のキャッシュ時の処理」を参照してください。

注意:

さらに、ビュー・オブジェクトは、行セットの行の挿入と削除に対応するために、RANGE_PAGING_AUTO_POSTアクセス・モードをサポートします。このモードはRANGE_PAGINGモードと同じように動作しますが、行セットに対してなんらかの変更が行われたときには常に、データベース・トランザクションでpostChanges()を呼び出すところが異なります。ただし、このモードは通常、同一のHTTPリクエスト内でのトランザクションのコミットまたはロールバックが必ず実行される場合を除き、Fusion Webアプリケーションでの使用には適していません。使用した場合、複数の異なるクライアントにより、アプリケーション・モジュールとデータベース接続の両方がプールされ、シリアルに共有されるという事態が環境内で発生する可能性があります。

9.10.1 上位N問合せのサポート方法の理解

Oracleデータベースは、問合せで順序付けされた最初のn行を効率よく返すための、上位N問合せと呼ばれる機能をサポートします。たとえば、次のような問合せがあるものとします。

SELECT EMPNO, ENAME,SAL FROM EMP ORDER BY SAL DESC

給与順に上位5人の従業員を取得する場合は、問合せを次のように記述できます。

SELECT * FROM (
   SELECT X.*,ROWNUM AS RN FROM (
      SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC 
   ) X
) WHERE RN <= 5

結果は次のようになります。

     EMPNO ENAME       SAL   RN
---------- -------- ------ ----
      7839 KING       5000    1
      7788 SCOTT      3000    2
      7902 FORD       3000    3
      7566 JONES      2975    4
      7698 BLAKE      2850    5

この機能は、順番に先頭のn行を取得できるだけではありません。一番外側のWHERE句の基準を調節することにより、問合せのソートされた順序で任意の範囲の行を効率よく取得できます。たとえば、問合せを次のように変更することで、6行目から10行目までを取得できます。

SELECT * FROM (
  SELECT X.*,ROWNUM AS RN FROM  (
     SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC
  ) X
) WHERE RN BETWEEN 6 AND 10

この考え方を一般化して、問合せ結果のPページ目を見たい場合は、1ページがR行であるとすると、次のような問合せを作成します。

SELECT * FROM (
  SELECT X.*,ROWNUM AS RN FROM (
    SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC
  ) X
) WHERE RN BETWEEN ((:P - 1) * :R) + 1 AND (:P) * :R

考えられる結果セットがより大きくなる場合、この手法を使用したページ移動の効率がさらに上がります。何百または何千もの行をデータベースからネットワーク経由で取得し、そのうちの10行のみをページに表示するかわりに、Pページ目のR行のみをデータベースから取得する賢明な問合せを作成できます。この方法を使用すると、ネットワーク経由で返す必要のある行数はほんのわずかで済みます。

このデータベース中心のページ移動方法をアプリケーションで実装するには、適切な問合せを自分で作成し、バインド変数:Rおよび:Pの適切な値を管理するコードを記述する必要があります。または、ビュー・オブジェクトの範囲ページ移動アクセス・モードを使用すると、このような機能が自動的に実装されます。

9.10.2 ビュー・オブジェクトの範囲ページ移動を有効にする方法

ビュー・オブジェクトの概要エディタの「チューニング」パネルを使用して、アクセス・モードを、標準の範囲ページ移動とインクリメンタル範囲ページ移動のいずれかに設定できます。「範囲ページング・インクリメンタル」を選択すると、「範囲ページング・キャッシュ・ファクタ」フィールドは編集のみ可能になります。図9-3に、ビュー・オブジェクトのアクセス・モードを示します。「範囲ページング」(標準モード)に設定されており、範囲サイズはデフォルトの1です。2つのアクセス・モードでの行セット・キャッシュの動作の詳細は、「範囲ページ移動を使用するときのビュー行のキャッシュ時の処理」を参照してください。

図9-3 ビュー・オブジェクトの概要エディタのアクセス・モード

この図は周囲のテキストで説明しています

ビュー・オブジェクトの標準範囲ページ移動をプログラム的に有効にするには、最初にsetRangeSize()をコールして1ページの行数を定義した後、必要に応じていずれかのモードで次のメソッドをコールします。

yourViewObject.setAccessMode(RowSet.RANGE_PAGING | RANGE_PAGING_INCR);

RANGE_PAGING_INCRを設定した場合、次のメソッドもコールして、定義済の範囲サイズに対してキャッシュ・ファクタを設定する必要があります。

yourViewObject.setRangePagingCacheFactor(int f);

9.10.3 範囲ページ移動を有効にしたときに行われる処理

ビュー・オブジェクトのアクセス・モードをRANGE_PAGINGに設定すると、ビュー・オブジェクトは次のような問合せをデフォルトとして使用します。

SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC

そして、これを自動的にラップし、上位N問合せを生成します。

最善のパフォーマンスのため、文ではBETWEEN演算子のかわりに、より大と、より小の基準の組合せが使用されますが、論理的な結果は、先に示した上位Nのラッピングの問合せと同じになります。基本になる問合せは次のようなものです。

SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC

これがラップされて、実際には次のような問合せが生成されます。

SELECT * FROM (
  SELECT /*+ FIRST_ROWS */ IQ.*, ROWNUM AS Z_R_N FROM (
    SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC
  ) IQ  WHERE ROWNUM < :0)
WHERE Z_R_N > :1

2つのバインド変数は、次のようにバインドされます。

  • :1は、現在のページの先頭行のインデックスです。

  • :0は、現在のページの最終行にバインドされます。

9.10.4 範囲ページ移動を使用するときのビュー行のキャッシュ時の処理

ビュー・オブジェクトがRANGE_PAGINGアクセス・モードで動作するとき、ビュー行キャッシュのメモリー内に一度に保持するのは、現在の行範囲(つまりページ)のみです。つまり、一度に10ずつ結果をページ移動する場合、最初のページでは、1から10行がビュー行キャッシュに保持されます。2ページ目に移動すると、キャッシュには11から20行が格納されます。これは、大きな行セットの場合に、単に前後にスクロールできるようにするという理由で大量の行がキャッシュされないようにするためにも役立ちます。

ビュー・オブジェクトがRANGE_PAGING_INCRアクセス・モードで動作するとき、特定の範囲サイズに対して、メモリーにキャッシュする行数は、キャッシュ・ファクタにより決まります。たとえば、範囲サイズを4、キャッシュ・ファクタを5に設定したとします。この場合、メモリーはコレクション中に最大4*5 = 20行を保持します。この例では、範囲が初めてリフレッシュされるとき、範囲ページ移動の問合せが行0 - 19(合計20行)を取得するためにバインドされていても、メモリーには4行のみが保持されます。範囲が4行目を過ぎてスクロールされると、より多くの行が現在の結果セットから読み込まれます。これが、20行すべてが問合せ結果から読み込まれるまで続きます。ユーザーのアクションにより次の行セットが取得される場合、新しい行番号バインド値で問合せが再実行されます。正確な行番号バインド値は、新しい範囲開始位置とキャッシュに保持できる行数で決まります。たとえば、20行すべてにデータが入っており、ユーザーが範囲開始位置を18 (0ベース)に移動するよう指示していると想定します。これは、メモリーが行18と行19を保持でき、範囲を満たすためにはあと2行必要であることを意味します。行20および21に対して問合せが再実行されます。

9.10.5 範囲ページ移動を使用して特定のページ番号にスクロールする方法

ビュー・オブジェクトがRANGE_PAGINGアクセス・モードで動作しているときに、ページ番号nにスクロールするには、scrollToRangePage()メソッドを呼び出し、パラメータ値としてnを渡します。

9.10.6 範囲ページ移動を使用するときの行セット内のページ数の推定方法

ビュー・オブジェクトがRANGE_PAGINGアクセス・モードで動作している場合、問合せ結果全体が生成する総ページ数の推定は、getEstimatedRangePageCount()メソッドを使用して取得できます。

9.10.7 範囲ページ移動モードを使用するときのトレードオフ

常にRANGE_PAGINGまたはRANGE_PAGING_INCRモードを使用すればよい、というわけではありません。それは、範囲ページ移動を使用すると、ビュー・オブジェクトの行を前後に移動したときに実行される問合せの総量が増加する可能性があるためです。次のような状況では、RANGE_PAGINGモードの使用を避ける必要があります。

  • 行セットのすべての行をただちに読み取ろうと考えている場合(たとえば、ドロップダウン・リストに移入するため)。

    この場合は、範囲サイズを-1に設定し、すべての行を含む単一のページのみが存在するため、範囲ページ移動のメリットはなくなります。

  • 小さいサイズの行セットで前後にページ移動する必要がある場合。

    行数が100以下で、RANGE_PAGINGモードを使用して10行ずつページ移動する場合、前後の新しいページに移動するために問合せが実行されます。デフォルトのスクロール可能モードでは、読み取ったビュー・オブジェクト行はキャッシュされ、前のページに戻る方向にページ移動しても、すでに表示された行を表示するために再び問合せが実行されることはありません。別の方法として、RANGE_PAGING_INCRモードを使用して、指定した行セット・キャッシュ・ファクタに基づいてメモリー内の結果をスクロールできるようにすることもできます。

非常に大きい(または予想不可能な大きさの)行セットの場合、問合せ(それぞれで、データベースから最大でRangeSizeの数だけ行が戻される)の実行回数が多少増える可能性があるというトレードオフは、表示済の行をすべてキャッシュすることに比べれば効率的です。結果のリストの任意のページにジャンプできるようにする場合は、このことが特に顕著です。デフォルトのスクロール可能モードでこれを行うには、現在のページとジャンプ先のページの間にあるすべての行をフェッチしてキャッシュする必要があります。RANGE_PAGINGモードでは、そのページの行をデータベースに要求するのみです。その後、ユーザーがすでに移動したことのあるページの行へ戻る場合、RANGE_PAGINGモードでは現在のページの行のみがメモリー内に保持されているため、これらの行は再度問合せる必要があります。このインクリメンタル範囲ページ移動アクセス・モード、RANGE_PAGING_INCRでは、標準の範囲ページ移動とスクロール可能アクセス・モードの両方の側面が組み合されています。アプリケーションはより多くの行をメモリーにキャッシュでき、ユーザーは再問合せする必要もなく、それらの行の任意の組合せにジャンプできます。

9.11 ビュー行のキャッシュを避ける前方のみモードの使用方法

行セットの各行を1回のみ読み取り、繰り返す必要がない場合は、前方検索のみモードをADFビュー・オブジェクトに設定できます。この手法により、取得された行のキャッシングが回避されます。

ビュー・オブジェクトの結果をプログラムで反復処理するコードを作成することがよくあります。よくある状況は、問合せ結果の複数の行を処理して属性またはエンティティが有効かどうかを判定する必要があるカスタム検証コードです。このような場合、行セット内の各行を1回のみ読み取り、戻る方向にスクロールしたり、後で行セットを再び反復処理したりする必要がない場合は、前方のみモードを使用することで、取得した行のキャッシュを回避できます。前方のみモードを有効にするには、ビュー・オブジェクトでsetForwardOnly(true)を呼び出します。

注意:

前方のみモードで読取り専用ビュー・オブジェクト(エンティティ・オブジェクトの慣用名がない)を使用し、フェッチ・サイズを適切にチューニングするのが、データをプログラムで読み取る最も効率のよい方法です。

また、行セットを後方にスクロールすることがなく、reset()を呼び出してイテレータを最初の行に設定することがない場合は、データを挿入、更新、または削除するときにも、前方のみモードを使用することで行のキャッシュを避けることができます。前方のみモードは、範囲サイズが1の場合にのみ機能します。

9.12 「行セットの保存」を使用したビュー・リンク・アクセッサのアクセスの最適化

ADFビュー・リンク・アクセサの行セットをデータベースの行で強制的にリフレッシュできます。これは、ビュー・リンク・アクセサの行セットにアクセスするたびに、データベース・ラウンドトリップなしにその行セットのオブジェクトにアクセスするためです。

デフォルトでは、ビュー・リンク・アクセッサの行セットを取得するたびに、ビュー・オブジェクトによって新しいRowSetオブジェクトが作成され、ユーザーが行を操作できるようにします。これは、そのたびに問合せを再実行して結果を生成するという意味ではなくRowSetオブジェクトの新しいインスタンスを作成してデフォルトのイテレータを先頭行の前のスロットにリセットするだけです。行セットをデータベースの行で強制的に更新するには、executeQuery()メソッドを呼び出します。

新しいディテール行セット作成に関連する若干のオーバーヘッドがアプリケーションで発生しないようにする場合は、ビュー・リンク・アクセッサ行セットのキャッシュを有効にできます。たとえば、ビュー・アクセッサ行セットは、マスター行ビュー・アクセッサ属性が変更されないかぎりは安定した状態を維持し、ツリー・コントロール(ツリー内の各マスター・ノードのデータが個別のディテール行セットを維持する必要がある)のようなUIコンポーネントの行セットを再作成する必要がありません。ビュー・リンク・アクセッサのディテール行セットにプログラムでアクセスすることもできます。この場合、アプリケーションで同じビュー・リンク・アクセッサ属性に対して多数のコールを行うときに、ビュー・リンク・アクセッサ行セットのキャッシングを検討できます。マスター/ディテール関係の管理のスタイルは、データ・モデルでのビュー・リンク・インスタンス作成とは異なります(「ビュー・リンク・アクセッサとデータ・モデル・ビュー・リンク・インスタンスの相違に関する必知事項」を参照)。

ビュー・リンク・アクセッサのソースであるビュー・オブジェクトについて、概要エディタを使用してビュー・リンク・アクセッサ行セットの保存を有効にできます。ビュー・オブジェクトの概要エディタの「ビュー・アクセッサ」ページで、「行セットの保存」を選択します。

かわりに、ビュー・オブジェクトでカスタムJavaクラスを有効にし、create()メソッドをオーバーライドして、パラメータとしてtrueを渡して、setViewLinkAccessorRetained()メソッドを呼び出す行を、super.create()の後に追加できます。これは、そのビュー・オブジェクトのすべてのビュー・リンク・アクセッサ属性に適用されます。

ビュー・オブジェクトに対してこの機能を有効にすると、ビュー・リンク・アクセッサの行セットが毎回再作成されないため、デフォルトの行セット・イテレータの現在行も維持されるという副作用があります。つまり、デフォルト行セット・イテレータの現在行をリセットして先頭行の前のスロットに戻すには、ビュー・リンク・アクセッサから取得した行セットに対して、reset()メソッドを明示的に呼び出す必要があります。

ただし、アクセッサの保持を有効にすると、アクセッサ行セットの行を反復処理する前にいつでもreset()を呼び出すようにしないと、微妙で検出が困難なエラーがアプリケーションで発生する可能性があることに注意してください。たとえば、ビュー・リンク・アクセッサの行セットの行を次のようにして反復処理し、合計を計算するものとします。

RowSet rs = (RowSet)row.getAttribute("OrdersShippedToPurchaser");
while (rs.hasNext()) {
  Row r = rs.next();
  // Do something important with attributes in each row
}

アクセッサ行セットを最初に処理するときには、このコードは正しく動作します。しかし、行セット(およびそのデフォルトの行セット・イテレータ)が保持されるため、2回目以降の行セットへのアクセスでは、現在行はすでに行セットの末尾にあり、rs.hasNext()falseになるためwhileループはスキップされます。この機能を有効にする場合は、アクセッサの反復コードは次のように記述する必要があります。

RowSet rs = (RowSet)row.getAttribute("OrdersShippedToPurchaser");
rs.reset(); // Reset default row set iterator to slot before first row!
while (rs.hasNext()) {
  Row r = rs.next();
  // Do something important with attributes in each row
}

ビュー・リンク一貫性が有効になっている場合は、アクセッサが保持されると、ポストされていない新しい行は行セットの最後に表示されます。これは、アクセッサが保持されない(デフォルト)場合と若干異なり、アクセッサが保持されないときは、ポストされていない新しい行は、アクセッサの行セットの先頭に表示されます。

9.13 UIの状態を格納するためのビュー・オブジェクトでの動的属性の使用方法

値としてシリアライズ可能オブジェクトを保持する動的属性をADFビュー・オブジェクトに追加できます。

addDynamicAttribute()メソッドを使用すると、実行時に1つまたは複数の動的属性をビュー・オブジェクトに追加できます。動的属性は、値として任意のシリアライズ可能オブジェクトを保持できます。通常は、グローバルで汎用的な方法でフレームワークに追加する機能を実装するために、行ごとに追加の一時的な状態を格納する必要がある、汎用のフレームワーク拡張コードを作成するときに、動的属性の使用を検討します。