11.1 LOBパフォーマンスのガイドライン

この項では、データ・インタフェースまたはLOB APIを介してLOBを使用する際のパフォーマンスのガイドラインを示します。

LOBには、データ・インタフェースを使用するかLOB APIを使用してアクセスできます。

11.1.1 すべてのLOB

この項では、LOBの使用時に良好なパフォーマンスを実現するためのガイドラインについて学習します。

次のガイドラインは、LOB使用時のパフォーマンスを最大にし、サーバーとのラウンドトリップの回数を最小にするために役立ちます。
  • I/Oを最小限にするには:

    • ブロック境界でデータの読取りおよび書込みを行います。これにより、UNDO生成を最小限にするなどの様々な方法でI/Oが最適化されます。一時LOBおよびSecureFile LOBの場合、表領域ブロック・サイズの使用可能データ領域は、PLSQLではDBMS_LOB.GETCHUNKSIZEというAPI、OCIではOCILobGetChunkSize()によって戻されます。ループで書き込む場合は、1つのデータベース・ブロックに書き込む必要があるすべての内容を1回の書込みコールで書き込むようにコードを設計し、それによって、同じブロックに連続的に書き込まれることがないようにします。

    • 一度に大量のデータの読取りおよび書込みを行います。

    • 前述の2つの推奨事項を組み合せて行うには、DBMS_LOB.GETCHUNKSIZE/OCILobGetChunkSize() APIによって返されたデータベース・ブロック・サイズに大きい整数を乗算したサイズで、読取りおよび書込みを行います。

  • サーバーとのラウンドトリップの回数を最小限にするには:
    • LOBデータの最大サイズを把握しており、LOB全体を読み取るか書き込む場合は、次に説明するように、データ・インタフェースを使用します。LOB全体のサイズを単一のバッファとして割り当てるか、ピース単位方式またはコールバック方式を使用することができます。

      • 読取り操作の場合は、OCIでOCIDefineByPos()関数、JDBCでDefineColumnType()関数を使用して、LOBを文字型またはバイナリ型として定義します。

      • 書込み操作の場合は、OCIでOCIBindByPos()関数、JDBCでsetString()メソッドまたはsetBytes()メソッドを使用して、LOBを文字型またはバイナリ型としてバインドします。

    • それ以外の場合は、次のようにLOB APIを使用します。

      • 読取りにはLOBのプリフェッチを使用します。その列に大部分のLOB値を含めることができるようにLOBプリフェッチ・サイズを定義します。

      • OCILobRead2操作またはOCILobWrite2操作を使用する際にピース単位方式またはコールバック方式を使用し、サーバーとのラウンドトリップを最小限にします。

11.1.2 永続LOB使用時のパフォーマンスに関するガイドライン

前述の、すべてのLOBに当てはまるパフォーマンス・ガイドラインに加え、ここでは、永続LOBを使用する際のパフォーマンス・ガイドラインを示します。

  • 1つのトランザクション内でコールを連続して行うことで、単一のLOBへの書込みを最大限にします。DML文をインターリーブすると、キャッシュの効率が最大に達するのが防止されます。
  • セーブポイントの作成やコミットは頻繁に実行しないでください。これにより、書込みの間のキャッシュの利点がなくなります。

ノート:

永続LOBの格納にはSecurefile LOBを使用することをお薦めしています。そのため、この章では、Securefileストレージのみに焦点を当てます。永続LOBに関する文脈では、LOBとは、他に示されていないかぎり、Securefile LOBを意味します。

11.1.3 一時LOB

前述のすべてのLOBに適用可能なパフォーマンス・ガイドラインに加えて、一時LOBの使用に関するガイドラインを次に示します。

  • 一時LOBは、サイズに応じてPGAメモリーまたは一時表領域に存在します。アプリケーションで使用される一時LOB用に十分なPGAメモリーおよび一時表領域があることを確認してください。

  • デフォルトのシステム表領域のかわりに、一時LOB記憶域に別の一時表領域を使用しますこれによって、データを永続LOBから一時LOBにコピーする場合のデバイスの競合を回避します。

    アプリケーションでLOBにSQLセマンティクスまたはPL/SQLセマンティクスを使用すると、多くの一時LOBがサイレントに作成されます。これらの一時LOBを格納するPGAメモリーおよび一時表領域が、アプリケーションに十分な大きさであることを確認してください。特に、これらの一時LOBが暗黙的に作成されるのは、次の事項を使用または実行する場合です。

    • LOBに対するSQLファンクション

    • LOBに対するPL/SQL組込み文字ファンクション

    • VARCHAR2からCLOBRAWからBLOBへの変数割当て。

    • LONGからLOBへの移行

  • SQL問合せおよびPL/SQLプログラムから戻された一時LOBを解放します

    PL/SQL、C (OCI)、Javaおよび他のプログラム・インタフェースでは、SQL問合せの結果またはPL/SQLプログラムの実行によって、LOBのオペレーション・コールおよびファンクション・コールに対して一時LOBが戻されます。たとえば:

    SELECT substr(CLOB_Column, 4001, 32000) FROM ... 
    

    PL/SQLで問合せが実行される場合、戻された一時LOBは、PL/SQLプログラム・ブロックの終了時に自動的に解放されます。任意の時点で、明示的に一時LOBを解放することもできます。OCIおよびJavaでは、戻された一時LOBを明示的に解放する必要があります。

    SQL問合せから戻された一時LOBの割当てを適切に解除しないと、パフォーマンスが低下する可能性があります。

  • PL/SQLでは、可能なかぎりNOCOPYを使用して、参照によって一時LOBパラメータを渡します。

    関連項目:

    参照によるパラメータの受渡しおよびパラメータのエイリアシングの詳細は、Oracle Database PL/SQL言語リファレンスを参照してください

  • CACHEパラメータをtrueに設定して作成された一時LOBは、バッファ・キャッシュ内を移動し、ディスク・アクセスを回避します。

  • すべてのオープン・セッションでの一時LOBの使用を監視するためのv$temporary_lobsビューが用意されています。例:
    SQL> select * from v$temporary_lobs;
    
           SID CACHE_LOBS NOCACHE_LOBS ABSTRACT_LOBS    CON_ID
    ---------- ---------- ------------ ------------- ----------
           141          2            3             4          0
           146          0            0             1          0
           148          0            0             1          0
    次に、出力の解釈を示します。
    • SID列は、セッションIDです。
    • CACHE_LOBS列は、CACHEがオンになっている一時表領域にセッション141の一時LOBが現在2つあることを示しています。
    • NOCACHE_LOBS列は、CACHEがオフになっている一時表領域にセッション141の一時LOBが現在3つあることを示しています。
    • ABSTRACT_LOBS列は、セッション141のPGAメモリーに現在4つの一時LOBがあることを示しています。
    • CON_ID列は、プラガブル・データベースのコンテナIDです。
  • 最適なパフォーマンスを実現するために、一時LOBでは、読取り時参照、書込み時コピーのセマンティクスが使用されます。一時LOBロケータが別のロケータに割り当てられる場合、物理LOBデータはコピーされません。どちらかのLOBロケータを使用する以降のREAD操作では、同じ物理LOBデータが参照されます。割当て後の最初のWRITE操作では、LOB値のセマンティクスを保ち、各ロケータが確実に一意のLOB値を指すように、物理LOBデータがコピーされます。

    PL/SQLでは、読取り時参照、書込み時コピーのセマンティクスは次のように示されます。

    LOCATOR1 BLOB; 
    LOCATOR2 BLOB; 
    DBMS_LOB.CREATETEMPORARY (LOCATOR1,TRUE,DBMS_LOB.SESSION); 
    
    -- LOB data is not copied in this assignment operation:  
    LOCATOR2 := LOCATOR;  
    -- These read operations refer to the same physical LOB copy: 
    DBMS_LOB.READ(LOCATOR1, ...); 
    DBMS_LOB.GETLENGTH(LOCATOR2, ...); 
    
    -- A physical copy of the LOB data is made on WRITE:  
    DBMS_LOB.WRITE(LOCATOR2, ...); 
    

    OCIでは、LOBロケータおよびデータの値セマンティクスを保証するために、OCILobLocatorAssign()を使用してLOBデータと一時LOBロケータがコピーされます。OCILobLocatorAssign()の場合、サーバーへのラウンドトリップは発生しません。物理的な一時LOBコピーは、次のように、LOB更新APIと同じラウンドトリップでLOBの更新が発生する場合に実行されます。

    OCILobLocator *LOC1;
    OCILobLocator *LOC2;
    OCILobCreateTemporary(... LOC1, ... TRUE,OCI_DURATION_SESSION);
    
    /* No round-trip is incurred in the following call. */
    OCILobLocatorAssign(... LOC1, LOC2);
    
    /* Read operations refer to the same physical LOB copy. */
    OCILobRead2(... LOC1 ...)
    
    /* One round-trip is incurred to make a new copy of the
     * LOB data and to write to the new LOB copy.
     */
    OCILobWrite2(... LOC1 ...)
    
    /* LOC2 does not see the same LOB data as LOC1. */
    OCILobRead2(... LOC2 ...)
    
    

    LOB値セマンティクスが意図されていない場合は、次のコード・スニペットに示すように、両方のロケータが同じデータを指すようにCポインタ割当てを使用できます。

    OCILobLocator *LOC1;
    OCILobLocator *LOC2;
    OCILobCreateTemporary(... LOC1, ... TRUE,OCI_DURATION_SESSION);
    
    /* Pointer is copied. LOC1 and LOC2 refer to the same LOB data. */
    LOC2 = LOC1;
    
    /* Write to LOC2. */
    OCILobWrite2(...LOC2...)
    
    /* LOC1 sees the change made to LOC2. */
    OCILobRead2(...LOC1...)
    
  • 一時LOBに対してOCI_OBJECTモードを使用します。

    LOB割当てでの一時LOBのパフォーマンスを向上させるには、OCILobLocatorAssign()に対してOCI_OBJECTモードを使用します。OCI_OBJECTモードでは、データベースはディープ・コピー回数を最小限にしようとします。そのため、OCI_OBJECTモードでソース一時LOBに対してOCILobLocatorAssign()が実行された後、ソース・ロケータおよび宛先ロケータは、いずれかのLOBロケータにより変更されるまで同一LOBを指すようになります。

11.1.4 値LOB

値LOBは一時LOBです。したがって、一時LOB記憶域に関するすべてのガイドラインが、値LOBにも当てはまります。

クライアント側で、値LOBについて、LOB読取りサイズの80%以上に対応できる大きさのLOBプリフェッチ・サイズを設定することをお薦めします。