10.2 応答時間短縮のための問合せの最適化
デフォルトでは、Oracle Textは問合せが最短時間ですべての行を戻すように、スループットの問合せを最適化します。
ただし、多くの場合(特にWebアプリケーションの場合)、問合せを応答時間が短縮されるように最適化する必要があります。これは大きなヒットリストからできるだけ短い時間で、最初の数個のヒットのみを取得する必要があるためです。
次の各項では、応答時間が短縮されるようにCONTAINS
問合せを最適化する方法を説明します。
10.2.1 問合せの応答時間に影響するその他の要因
問合せの応答時間に影響を与える要因として、次のものが考えられます。
-
表統計の収集
-
メモリー割当て
-
ソート
-
元表に存在するラージ・オブジェクト(LOB)列
-
パーティション化
-
並列度
-
問合せで語句を拡張する回数
関連項目:
10.2.2 FIRST_ROWS(n)ヒントによるORDER BY問合せの応答時間の短縮
ORDER BY
問合せの最初のいくつかの行が必要な場合は、コストベースであるFIRST_ROWS(n)
ヒントを使用することをお薦めします。
ノート:
FIRST_ROWS(n)
ヒントはコストベースであるため、使用する前に表に関する統計を収集しておくことをお薦めします。
FIRST_ROWS(n)
ヒントは、最初のn行をできるだけ短時間で受け取る必要がある場合に使用します。たとえば、次のPL/SQLブロックでは、カーソルを使用して問合せの最初の10ヒットを取り出し、FIRST_ROWS(n)
ヒントを使用して応答時間が短縮されるように最適化しています。
declare cursor c is select /*+ FIRST_ROWS(10) */ article_id from articles_tab where contains(article, 'Omophagia')>0 order by pub_date desc; begin
for i in c loop insert into t_s values(i.pk, i.col); exit when c%rowcount > 11; end loop;
end; /
c
カーソルは、omophagiaというワードを含むソートされたROWIDを戻すSELECT
文です。コードがカーソル内をループして、最初の10行を取り出します。取り出された行は、一時t_s
表に格納されます。
FIRST_ROWS(n)
ヒントを指定した場合、オプティマイザは上位n個のヒットを戻すコストが低い場合に、Oracle Text索引に対してROWIDをスコア順で戻すように指示します。
このヒントがない場合、Oracle Text索引によりCONTAINS
述語を満たすすべての行がソートされていない順序で戻された後、Oracle DatabaseによりROWIDがソートされます。結果セット全体を取り出すと時間がかかります。
この問合せでは、最初の10ヒットのみが必要なため、ヒントを使用することでパフォーマンスが向上します。
ノート:
FIRST_ROWS(n)
ヒントは、問合せで最初の数個のヒットのみが必要な場合に使用します。結果セット全体が必要な場合は、パフォーマンスの低下につながるため、このヒントは使用しないでください。
10.2.3 DOMAIN_INDEX_SORTヒントを使用した応答時間の短縮
また、DOMAIN_INDEX_SORT
ヒントを使用して応答時間を短縮することもできます。FIRST_ROWS(n)
の場合と同じように、応答時間が短縮されるように問合せが最適化されている場合は、Oracle Textは最初の数行を最短時間で戻します。
たとえば、このヒントは次のように使用できます。
select /*+ DOMAIN_INDEX_SORT */ pk, score(1), col from ctx_tab where contains(txt_col, 'test', 1) > 0 order by score(1) desc;
ただし、このヒントはルールベースのみです。つまり、Oracle Textでは、ORDER BY
句を満たす索引を常に選択します。このヒントにより、CONTAINS
句の選択性が非常に高い問合せでは、パフォーマンスが最善にはならないことがあります。そのような場合は、完全にコストベースのFIRST_ROWS(n)
ヒントを使用することをお薦めします。
10.2.4 ローカル・パーティションCONTEXT索引を使用した応答時間の短縮
データをパーティション化し、ローカル・パーティション索引を作成すると、問合せのパフォーマンスが向上します。パーティション表では、各パーティションに独自の索引表セットがあります。実際には複数の索引がありますが、結果が必要に応じて組み合され、最終的な結果セットが生成されます。
LOCAL
キーワードを使用して、CONTEXT
索引を次のように作成します。
CREATE INDEX index_name ON table_name (column_name) INDEXTYPE IS ctxsys.context PARAMETERS ('...') LOCAL
パーティション化された表および索引を使用すると、次のような問合せのパフォーマンスが向上します。
-
パーティション・キー列の範囲検索: この問合せは、パーティション・キーでもある列の特定の値範囲に検索を限定します。たとえば、日付範囲に対する次の問合せについて考えます。
SELECT storyid FROM storytab WHERE CONTAINS(story, 'oliver')>0 and pub_date BETWEEN '1-OCT-93' AND '1-NOV-93';
日付範囲が制限されている場合は、1つのパーティションを検索するだけで問合せが満たされる可能性があります。
-
ORDER BYパーティション・キー列: これは、最初の
n
個のヒットのみが必要で、ORDER BY
句がパーティション・キーを指定します。次のように、price
列に対するORDER BY
問合せで最初の20ヒットをフェッチする場合を考えてみます。SELECT * FROM (
SELECT itemid FROM item_tab WHERE CONTAINS(item_desc, 'cd player') >0 ORDER BY price) WHERE ROWNUM < 20;
この例では、表はpriceによりパーティション化されており、最初のパーティションからのヒットを取得すれば問合せが満たされる可能性があります。
10.2.5 スコア順のローカル・パーティション索引を使用した応答時間の短縮
ローカル・パーティション索引に対するDOMAIN_INDEX_SORT
ヒントにより、特にスコア順にした場合にパフォーマンスが大幅に低下することがあります。結果をソートする前に、全パーティションにまたがる問合せの全ヒットを取得する必要があります。
かわりに、DOMAIN_INDEX_SORT
ヒントを使用するときにインライン・ビューを使用します。DOMAIN_INDEX_SORT
ヒントを使用すると、次のような条件下で、ローカル・パーティション表の問合せパフォーマンスが向上します。
-
SCORE()
句による順序を含むOracle Text問合せ自体がインライン・ビューとして表されている場合。 -
インライン・ビュー内のOracle Text問合せに
DOMAIN_INDEX_SORT
ヒントが含まれている場合。 -
インライン・ビューに対する問合せに、ビューからフェッチする行数を制限する
ROWNUM
述語が含まれている場合。
たとえば、パーティション表doc_tab
に対して、次のOracle Text問合せとローカルOracle Text索引が作成されます。
select doc_id, score(1) from doc_tab where contains(doc, 'oracle', 1)>0 order by score(1) desc;
上位20行のみを取り出す場合は、この問合せを次のように再作成します。
select * from (select /*+ DOMAIN_INDEX_SORT */ doc_id, score(1) from doc_tab where contains(doc, 'oracle', 1)>0 order by score(1) desc) where rownum < 21;
関連項目:
EXPLAIN PLAN
文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。
10.2.6 問合せフィルタ・キャッシュを使用した応答時間の短縮
Oracle Textには、問合せ結果のキャッシュに使用できる、問合せフィルタ・キャッシュというキャッシュ・レイヤーがあります。問合せフィルタ・キャッシュは、問合せ間で共有が可能です。キャッシュされた問合せ結果を複数の問合せで再利用して、問合せの応答時間を短縮できます。
キャッシュする問合せ結果を指定するには、ctxfiltercache
演算子を使用します。次の例では、この演算子を使用して、common_predicate
問合せの結果をキャッシュに格納しています。
select * from docs where contains(txt, 'ctxfiltercache((common_predicate), FALSE)')>0;
この例では、common_predicate
問合せの結果がキャッシュされ、new_query
問合せによって再利用されます。そのため、問合せの応答時間が短縮されます。
select * from docs where contains(txt, 'new_query & ctxfiltercache((common_predicate), FALSE)')>0;
ノート:
ノート:
CTXFILTERCACHE
問合せ演算子は、問合せでよく使用される式を高速化するために設計されました。Oracle Databaseリリース21cでは、この機能は他の内部の改善によって置き換えられています。CTXFILTERCACHE
演算子は非推奨です(また、そのオペランドを通過して通常の問合せとして実行されます)。それらには機能がないため、ビューCTX_FILTER_CACHE_STATISTICS
も記憶域属性QUERY_FILTER_CACHE_SIZE
も非推奨です。
関連項目:
詳細は、『Oracle Textリファレンス』を参照してください。
-
ctxfiltercache
演算子 -
query_filter_cache_size
基本記憶域属性 -
ctx_filter_cache_statistics
ビュー
10.2.7 CONTEXT索引のBIG_IOオプションを使用した応答時間の短縮
Oracle Textに用意されているBIG_IO
オプションを使用すると、CONTEXT
索引でIO操作が多用される場合の、問合せのパフォーマンスを改善できます。
問合せパフォーマンスが向上するのは、主として回転ディスク上に格納されているデータの場合であり、SSDに格納されているデータについてはあまり効果がありません。
BIG_IO
オプションを有効にすると、CONTEXT
索引では一意のトークン・テキストごとに1つのラージ・オブジェクト(LOB)データ型を伴うトークン・タイプ・ペアが作成されます。テキストが同じでトークン・タイプが異なるトークンは、$I
表で対応する行が異なります。
ノート:
CONTEXT
索引タイプのBIG_IO
属性は、Oracle Database 23aiで非推奨になり、将来のリリースで無効化または削除される可能性があります。
Oracleでは、この値をデフォルト値N
に設定することをお薦めします。BIG_IO
は、索引ポストの長さが4KBを超えた場合にシークのコストを削減するために導入されました。ただし、内部コードは比較的非効率であり、属性を新しい索引オプションと組み合せることはできません。シーク・コストは、ソリッド・ステート・ディスクまたは非揮発性メモリー・デバイス(NVMe)にはあまり関連せず、ポストがキャッシュされている場合、シーク・コストは関係ありません。したがって、この設定はほとんどの索引にとってほとんどメリットがありません。
BIG_IO
オプションが有効になっている索引には、SecureFile LOBとして作成されたトークンLOBが必要です。これにより、データが複数のブロックに順次格納されます。この方法により、問合せで短い読取りを何度も実行するかわりに、連続した長い読取りを実行できるため、問合せの応答時間が短縮されます。
ノート:
SecureFilesを使用する場合は、COMPATIBLE
設定を11.0以上に設定する必要があります。また、自動セグメント領域管理(ASSM)の表領域にLOBを作成する必要があります。既存のOracle Text索引をSecureFilesに移行する場合は、ASSM表領域を使用します。既存の索引をSecureFilesに移行しやすくするために、$I表にのみ影響する記憶域プリファレンスを提供するようにALTER INDEX REBUILD
を拡張できます。
BIG_IO
索引オプションを指定してCONTEXT
索引を作成するには、まずBIG_IO
記憶域属性の値をYES
に設定して基本記憶域プリファレンスを作成し、CONTEXT
索引の作成時にこの記憶域プリファレンスを指定します。
次の例は、mystore
基本記憶域プリファレンスを作成し、そのBIG_IO
記憶域属性の値をYESに設定します。
exec ctx_ddl.create_preference('mystore', 'BASIC_STORAGE'); exec ctx_ddl.set_attribute('mystore', 'BIG_IO', 'YES');
BIG_IO
オプションを無効にするには、BIG_IO
記憶域属性の値をNO
に設定して既存の記憶域プリファレンス(mystore
)を更新してから、索引を再構築します。
exec ctx_ddl.set_attribute('mystore', 'BIG_IO', 'NO'); alter index idx rebuild('replace storage mystore');
警告:
メタデータ置換操作を使用して、BIG_IO
索引オプションを無効にしないでください。索引で矛盾が生じる場合があります。
索引を再構築せずにパーティション索引でBIG_IO
オプションを有効にするには、BIG_IO
記憶域属性の値をYES
に設定して基本記憶域プリファレンスを変更し、ctx_ddl.replace_index_metadata,
を使用してグローバル索引メタデータを置き換えてから、パーティション索引表のパーティションごとにREBUILD
モードでoptimize_index
をコールします。
次の例では、idx
パーティション索引に対してBIG_IO
オプションを有効にします。
exec ctx_ddl.set_attribute('mystore', 'BIG_IO', 'YES'); exec ctx_ddl.replace_index_metadata('idx', 'replace metadata storage mystore'); exec ctx_ddl.optimize_index('idx', 'rebuild', part_name=>'part1');
ノート:
BIG_IO
オプションのみを有効にして既存の索引表を変更するプロシージャでは、データの再索引付けは行われません。
ノート:
BIG_IO
索引オプションは連続した長い読取りを実行するので、BIG_IO
索引オプションを使用する問合せでは、必要なプログラム・グローバル領域(PGA)のメモリーが多くなります。
10.2.8 CONTEXT索引のSEPARATE_OFFSETSオプションを使用した応答時間の短縮
Oracle Textに用意されているSEPARATE_OFFSETS
オプションを使用すると、CONTEXT
索引でIO操作が使用されその問合せが主に単一語またはブールの問合せである場合の、問合せパのフォーマンスを改善できます。
SEPARATE_OFFSETS
オプションでは、TEXTタイプのトークンに対して作成されるポスト・リストの構造が異なります。
DOCID、頻度、情報の長さ(オフセット情報の長さ)およびオフセットをポスト・リストに分散させるかわりに、SEPARATE_OFFSETS
オプションではDOCIDと頻度をすべてポスト・リストの最初に格納し、情報の長さとオフセットをすべてポスト・リストの最後に格納します。ポストの先頭にあるヘッダーには、DOCIDとオフセットの間の境界点に関する情報が含まれています。DOCIDとオフセットを分離すると、データを読み取る問合せの時間が短くなるため、問合せの応答時間が短縮されます。
SEPARATE_OFFSETS
オプションを指定してCONTEXT
索引を作成するには、まずSEPARATE_OFFSETS
記憶域属性の値をT
に設定して基本記憶域プリファレンスを作成します。次に、CONTEXT
索引の作成時に、この記憶域プリファレンスを指定します。
次の例は、mystore
基本記憶域プリファレンスを作成し、そのSEPARATE_OFFSETS
記憶域属性の値をTに設定します。
exec ctx_ddl.create_preference('mystore', 'BASIC_STORAGE'); exec ctx_ddl.set_attribute('mystore', 'SEPARATE_OFFSETS', 'T');
SEPARATE_OFFSETS
オプションを無効にするには、SEPARATE_OFFSETS
記憶域属性の値をF
に設定して既存の記憶域プリファレンス(mystore
)を更新してから、索引を再構築します。
exec ctx_ddl.set_attribute('mystore', 'SEPARATE_OFFSETS', 'F'); alter index idx rebuild('replace storage mystore');
警告:
索引で矛盾が生じるので、SEPARATE_OFFSETS
索引オプションの無効化にメタデータ置換操作は使用しないでください。
索引を再構築せずにパーティション索引でSEPARATE_OFFSETS
オプションを有効にするには、SEPARATE_OFFSETS
記憶域属性の値をT
に設定して基本記憶域プリファレンスを変更し、ctx_ddl.replace_index_metadata,
を使用してグローバル索引メタデータを置き換えてから、パーティション索引表のパーティションごとにREBUILDモードでoptimize_index
をコールします。
次の例では、idx
パーティション索引に対してSEPARATE_OFFSETS
オプションを有効にします。
exec ctx_ddl.set_attribute('mystore', 'SEPARATE_OFFSETS', 'T'); exec ctx_ddl.replace_index_metadata('idx', 'replace storage mystore'); exec ctx_ddl.optimize_index('idx', 'rebuild', part_name=>'part1');
ノート:
SEPARATE_OFFSETS
オプションのみを有効にして既存の索引表を変更するプロシージャでは、データの再索引付けは行われません。
10.2.9 CONTEXT索引のSTAGE_ITAB、STAGE_ITAB_MAX_ROWS、STAGE_ITAB_PARALLELオプションを使用した応答時間の短縮
Oracle Textに用意されているSTAGE_ITAB
オプションを使用すると、CONTEXT
索引および検索索引でほぼリアルタイムの索引付けのために挿入、更新および削除の操作が多用される場合の、問合せのパフォーマンスを改善できます。
STAGE_ITAB
オプションは、検索索引についてのみ、デフォルトの索引オプションとなります。
STAGE_ITAB
索引オプションを使用しない場合は、新しいドキュメントをCONTEXT
索引に追加するたびに、ドキュメントを検索可能にするためにSYNC_INDEX
がコールされます。このコールは、$I
表に新しい行が作成されるため、$I
表で断片化が大きくなります。その結果、問合せのパフォーマンスが低下します。
STAGE_ITAB
索引オプションを有効にすると、次の処理が行われます。
-
新しいドキュメントに関する情報は、
$I
表ではなく$G
ステージング表に格納されます。このストレージによって$I
表は断片化しなくなるため、問合せパフォーマンスが低下しません。 -
$H
Bツリー索引は、$G
表に作成されます。$G
表と$H
Bツリー索引は、$I
表と$X
Bツリー索引と同等です。
$G
表の行数が記憶域設定STAGE_ITAB_MAX_ROWS
(デフォルトは1万)を超えると、$G
表から$I
表に行が自動的にマージされます。MERGE
最適化モードで索引最適化を実行することによって、$G
から$I
への行の即時マージを強制することもできます。
ノート:
$G
表は、KEEP
プールに格納されます。問合せパフォーマンスを改善するには、十分なKEEP
プール・メモリーを割り当て、新しいstage_itab_max_rows
オプションを使用して十分な大きさの$G
表を維持する必要があります。
STAGE_ITAB
索引オプションを指定してCONTEXT
索引を作成するには、まずSTAGE_ITAB
記憶域属性の値をYES
に設定して基本記憶域プリファレンスを作成します。次に、CONTEXT
索引の作成時に、この記憶域プリファレンスを指定します。
次の例は、mystore
基本記憶域プリファレンスを作成し、そのSTAGE_ITAB
記憶域属性の値をYES
に設定します。
exec ctx_ddl.create_preference('mystore', 'BASIC_STORAGE'); exec ctx_ddl.set_attribute('mystore', 'STAGE_ITAB', 'YES');
ALTER INDEX
文の再構築オプションを使用すれば、パーティション化されていない既存のCONTEXT
索引に対してSTAGE_ITAB
索引オプションを有効にすることもできます。
alter index IDX rebuild parameters('replace storage mystore');
パーティション化されていないCONTEXT
索引に対してSTAGE_ITAB
オプションを無効にするには、STAGE_ITAB
記憶域属性の値をNO
に設定して既存の記憶域プリファレンス(mystore
)を更新してから、索引を再構築します。
exec ctx_ddl.set_attribute('mystore', 'STAGE_ITAB', 'NO'); alter index idx rebuild parameters('replace storage mystore');
この操作は、MERGE
最適化モードを使用して最適化プロセスを実行してから、$G
表を削除します。
ALTER INDEX
文の再構築オプションを、パーティション化されているCONTEXT
索引に使用して、STAGE_ITAB
オプションの有効化と無効化を行うことはできません。
次の例は、CONTEXT
パーティション索引idx
に対してSTAGE_ITAB
オプションを有効にします。
alter index idx parameters('add stage_itab');
次の例は、CONTEXT
パーティション索引idx
に対してSTAGE_ITAB
オプションを無効にします。
alter index idx parameters('remove stage_itab');
$G
の行数がOracle Database 12cリリース2 (12.2)では100万、Oracle Databaseリリース18cでは10万を超えている場合は、索引の同期中に、$G
の内容が自動的に$I
に移動されました。Oracle Databaseリリース21c以降では、デフォルトでは、$G
の行数が1万を超えている場合は、索引の同期中に$G
の内容が自動的に$I
に移動されます。この値は、STORAGE
プリファレンスのSTAGE_ITAB_MAX_ROWS
属性により制御されます。
ノート:
CONTEXT
索引にSTAGE_ITAB
索引オプションを使用するには、g_index_clause
およびg_table_clause
BASIC_STORAGE
プリファレンスを指定する必要があります。
$G
表の断片化が進むと、問合せのパフォーマンスが低下します。低下を回避するために、Oracle Databaseリリース18c以降、Oracle Textではすべての索引またはパーティションに対する自動バックグラウンド最適化マージ機能が提供されています。自動バックグラウンド最適化マージを有効にするには、STAGE_ITAB
記憶域プリファレンス属性をTRUE
に設定し、STAGE_ITAB
属性を使用する記憶域プリファレンスで索引を作成する必要があります。
デフォルトでは、Oracle Databaseリリース18cにアップグレードする前に、索引でSTAGE_ITAB
を有効化した場合、STAGE_ITAB_AUTO_OPT
は有効化されません。既存の索引でSTAGE_ITAB
およびAUTO_OPTIMIZE
が有効になっている場合は、STAGE_ITAB_AUTO_OPT
を有効化する前にAUTO_OPTIMIZE
を無効にする必要がありますOracle Databaseリリース19c以降では、自動バックグラウンド最適化マージのSTAGE_ITAB_AUTO_OPT
は、デフォルトではTRUE
に設定されています。STAGE_ITAB_AUTO_OPT
をFALSE
に設定した場合は、そのマージはSYNC INDEX
の一部として実行されます。AUTO_OPTIMIZE
を使用するかわりにSTAGE_ITAB
およびSTAGE_ITAB_AUTO_OPT
をTRUE
に設定することをお薦めします。
ノート:
Oracle Databaseリリース21cでは、プロシージャADD_AUTO_OPTIMIZE
およびREMOVE_AUTO_OPTIMIZE
と、ビューCTX_AUTO_OPTIMIZE_INDEXES
、CTX_USER_AUTO_OPTIMIZE_INDEXES
およびCTX_AUTO_OPTIMIZE_STATUS
は非推奨です。
次の例は、mystore
基本記憶域プリファレンスを作成し、そのSTAGE_ITAB_AUTO_OPT
記憶域属性の値をTRUE
に設定します。
exec ctx_ddl.create_preference('mystore', 'basic_storage');
exec ctx_ddl.set_attribute('mystore', 'stage_itab', 'TRUE');
exec ctx_ddl.set_attribute('mystore', 'stage_itab_auto_opt', 'TRUE');
exec ctx_ddl.set_attribute('mystore', 'stage_itab_parallel', 16);
関連トピック