この章では、問合せおよび索引付けのパフォーマンスを改善する方法について説明します。次の項目について説明します。
統計を使用して問合せを最適化する場合は、問合せ表および索引に関して収集された統計を使用して、その問合せを最も効率的に処理できる実行計画が選択されます。一般に、問合せパフォーマンスの改善が必要な場合は、元表に関する統計を収集することをお薦めします。
オプティマイザは、次のパラメータに基づいて最適な実行計画を選択します。
CONTAINS
述語の選択性
同じ問合せに含まれるその他の述語の選択性
CONTAINS
述語を処理したときのCPUコストとI/Oコスト
注意: Oracle Text索引などの、ドメイン索引に関する統計のインポートおよびエクスポートは、 DBMS_STATS パッケージではサポートされていません。統計のインポートおよびエクスポートの詳細は、『PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。 |
次の各項では、統計を拡張可能問合せオプティマイザで使用する方法を説明します。統計を使用して最適化を行うと、CONTAINS
述語の選択性およびコストをより正確に見積ることができるため、より適切な実行計画が選択されます。
デフォルトでは、Oracle Textはコストベース・オプティマイザ(CBO)を使用し、問合せに対する最適な実行計画を決定します。オプティマイザを使用して最適なコストを見積るために、問い合せる表の統計を計算できます。そのためには、次の文を入力します。
ANALYZE TABLE <table_name> COMPUTE STATISTICS;
また、次のように表のサンプルの統計を見積ることができます。
ANALYZE TABLE <table_name> ESTIMATE STATISTICS 1000 ROWS;
または
ANALYZE TABLE <table_name> ESTIMATE STATISTICS 50 PERCENT;
統計の収集は、DBMS_STATS.GATHER_TABLE_STATS
プロシージャを使用してパラレルに行うこともできます。
begin
DBMS_STATS.GATHER_TABLE_STATS('owner', 'table_name', estimate_percent=>50, block_sample=>TRUE, degree=>4) ;
end ;
これらの文は、table_name
に関連付けられたすべてのオブジェクトの統計を収集します。オブジェクトには、その表の列とその表に関連付けられたすべての索引(Bツリー、ビットマップまたはテキスト・ドメイン)も含まれます。
表の統計を再収集するには、ANALYZE
文を必要な回数入力するか、DBMS_STATS
パッケージを使用します。
テキスト・ドメイン索引の統計を収集することによって、Oracle Databaseのコストベース・オプティマイザでは、次のタスクを実行できます。
CONTAINS
述語の選択性の見積り
テキスト索引を使用したときのI/OコストとCPUコスト(ドメイン索引を使用してCONTAINS
述語を処理するときのコスト)の見積り
CONTAINS
の起動ごとのI/OコストとCPUコストの見積り
CONTAINS
述語の選択性がわかっていると、構造化問合せなど、複数の述語が含まれた問合せを行う場合に役立ちます。このように、コストベース・オプティマイザでは、ドメイン索引を使用してCONTAINS
を評価するか、あるいはCONTAINS
述語をポスト・フィルタとして適用するかを、より適切に判断できます。
次の構造化問合せについて考えます。
select score(1) from tab where contains(txt, 'freedom', 1) > 0 and author = 'King' and year > 1960;
author
列はVARCHAR2
型で、year
列はNUMBER
型であるとします。また、author
列にはBツリー索引があるとします。
さらに、構造化されたauthor
述語は、CONTAINS
述語およびyear
述語よりも選択性が高いと想定します。つまり、構造化述語(author = 'King'
)は、year
述語およびCONTAINS
述語と比較して、かなり少ない数の行(たとえば、それぞれ1000行および1500行に対して5行)を戻すと想定します。
このような状況の場合、Oracle Textでは、最初に構造化述語(author = 'King'
)にBツリー索引のレンジ・スキャンを行い、次にROWIDで表アクセスを行った後、Bツリーの表アクセスから戻された行に他の2つの述語を適用することで、この問合せをより効率的に行うことができます。
注意: テキスト索引の統計が収集されていない場合、コストベース・オプティマイザは、 CONTAINS 述語の選択性と索引コストが低いものとみなします。 |
索引を同期化した後、単一の索引の統計を再収集して、コストの見積りを更新できます。
同期化の前に元表が再解析されている場合は、同期化の後に表全体を再解析しなくても、索引を解析するのみで十分です。
そのためには、次の文のいずれかを入力します。
ANALYZE INDEX <index_name> COMPUTE STATISTICS; または ANALYZE INDEX <index_name> ESTIMATE STATISTICS SAMPLE 1000 ROWS; または ANALYZE INDEX <index_name> ESTIMATE STATISTICS SAMPLE 50 PERCENT;
デフォルトでは、Oracle Textにより、問合せはスループット向上のために最適化されます。最適化の結果、問合せは最短時間ですべての行を戻します。
ただし、多くの場合(特にWebアプリケーションの場合)、問合せを応答時間が短縮されるように最適化する必要があります。これは大きなヒットリストからできるだけ短い時間で、最初の数個のヒットのみを取得する必要があるためです。
次の各項では、応答時間が短縮されるようにCONTAINS
問合せを最適化する方法を説明します。
次のような要因が問合せ応答時間に影響します。
表統計の収集
メモリー割当て
ソート
元表に存在するLOB列
パーティション化
並列性
問合せで語句を拡張する回数
ORDER BY
問合せの最初のいくつかの行が必要な場合は、コストベースである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
ヒントを指定した場合、Oracle Textはテキスト索引に対して(可能な場合)ROWIDをスコア順で戻すように指示します。
このヒントがない場合は、テキスト索引がCONTAINS
述語を満たすすべての行をソートされていない状態で戻した後で、Oracle TextがROWIDをソートします。このように結果セット全体を取り出すと時間がかかります。
この問合せでは、最初の10ヒットのみが必要なため、ヒントを使用することでパフォーマンスが向上します。
注意: FIRST_ROWS(n) ヒントは、問合せで最初の数個のヒットのみが必要な場合に使用します。結果セット全体が必要な場合は、パフォーマンスの低下につながるため、このヒントは使用しないでください。 |
また、FIRST_ROWS
ヒントを使用して応答時間を短縮することもできます。FIRST_ROWS(n)
の場合と同じように、応答時間が短縮されるように問合せが最適化されている場合は、Oracle Textは最初の数行を最短時間で戻します。
たとえば、このヒントは次のように使用できます。
select /*+ FIRST_ROWS */ 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)
ヒントを使用することをお薦めします。
データをパーティション化し、ローカル・パーティション索引を作成すると、問合せのパフォーマンスが向上します。パーティション表では、各パーティションに独自の索引表セットがあります。実際には複数の索引がありますが、各索引からの結果が必要に応じて組み合され、最終的な結果セットが生成されます。
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つのパーティションを検索するだけで問合せが満たされる可能性があります。
これは、最初の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によりパーティション化されており、最初のパーティションからのヒットを取得すれば問合せが満たされる可能性があります。
ローカル・パーティション索引に対してFIRST_ROWS
ヒントを使用すると、特にスコア順にした場合にパフォーマンスが大幅に低下することがあります。これは、結果をソートする前に、全パーティションにまたがる問合せの全ヒットを取得する必要があるためです。
パフォーマンスの低下を回避するには、FIRST_ROWS
ヒントを使用するときにインライン・ビューを使用します。FIRST_ROWS
ヒントを使用すると、次のような条件下で、ローカル・パーティション表の問合せパフォーマンスを向上させることができます。
SCORE()
句による順序を含むテキスト問合せ自体がインライン・ビューとして表されている場合
インライン・ビュー内のテキスト問合せにFIRST_ROWS
ヒントまたはDOMAIN_INDEX_SORT
ヒントが含まれている場合
インライン・ビューに対する問合せに、ビューからフェッチする行数を制限するROWNUM
述語が含まれている場合
たとえば、次のテキスト問合せがあり、パーティション表doc_tabに対してローカル・テキスト索引が作成されているとします。
select doc_id, score(1) from doc_tab where contains(doc, 'oracle', 1)>0 order by score(1) desc;
ここで、上位20行のみを取り出す場合は、この問合せを次のように再作成します。
select * from (select /*+ FIRST_ROWS */ doc_id, score(1) from doc_tab where contains(doc, 'oracle', 1)>0 order by score(1) desc) where rownum < 21;
問合せがスループット向上のために最適化された場合は、すべてのヒットが最短時間で戻されます。これはデフォルトの動作です。
次の各項では、スループット向上のために明示的に最適化する方法を説明します。
デフォルトでは、問合せはCHOOSE
モードおよびALL_ROWS
モードでスループットが向上するように最適化されます。問合せがスループット向上のために最適化された場合は、Oracle Textにより、すべての行が最短時間で戻されます。
FIRST_ROWS
モードでは、可能な場合、テキスト・ドメイン索引にスコア順にソートされた行を戻させることによって応答時間を短縮するように、Oracle Databaseのオプティマイザが最適化します。これは、FIRST_ROWS
ヒントを使用する場合のデフォルトの動作です。
FIRST_ROWS
でスループットがさらに向上するように最適化するには、DOMAIN_INDEX_NO_SORT
ヒントを使用します。スループットの向上とは、すべての行を最短時間で問合せに取り込むことです。
次の例では、スコア順にソートした行を戻すためにテキスト・ドメイン索引を使用せずにスループットを向上させています。かわりに、CONTAINS
述語を満たすすべての行が索引から取り出された後で、Oracle Textによって行がソートされます。
select /*+ FIRST_ROWS DOMAIN_INDEX_NO_SORT */ pk, score(1), col from ctx_tab where contains(txt_col, 'test', 1) > 0 order by score(1) desc;
Oracle Database 11gの拡張性フレームワークのコンポジット・ドメイン索引機能を使用すると、構造化された列をOracle Textで索引付けできます。したがって、テキストと1つ以上の構造化された条件の両方が、Oracle Textの単一の索引の行ソースによって満たされます。次のタイプの問合せのパフォーマンスが向上します。
SQL WHERE
句内の、構造化された条件を持つテキスト問合せ
構造化されたORDER
BY
条件を持つテキスト問合せ
前述の2つの問合せタイプの両方の組合せ
連結されたBツリー索引やビットマップ索引と同様、FILTER
BY
列およびORDER
BY
列の数が増えるに従って、アプリケーションではDMLのパフォーマンスが低下します。SCORE
によるソートのプッシュダウンが応答時間の短縮のために最適化されている場合、構造化されたソートまたはSCORE
と構造化されたソートの組合せのプッシュダウンも同様に、スループットの向上ではなく応答時間の短縮のために最適化されます。ただし、FIRST_ROWS
ヒントまたはFIRST_ROWS
(n)
ヒントを使用してフェッチ中にCDIにソートを含めるよう強制した場合、ヒットリスト全体を表示するには問合せ応答時間が大幅にかかります。
FILTER
BY
列のMDATA
へのマッピングがサポートされているため、RANGE
およびLIKE
のサポートされた機能を制限することで、問合せのパフォーマンスは等価性検索に対して最適化されます。ただし、FILTER
BY
列が連続した値を含むかまたはそのカーディナリティが非常に高い場合は、FILTER
BY
列のMDATA
へのマッピングはお薦めしません。このマッピングを実行した場合、非常に細長い$I
表が作成され、$X
のパフォーマンスが低下します。このような連続した列の一例として、DATE
スタンプを使用した場合があります。このような連続した列の場合は、SDATA
へのマッピングをお薦めします。
SORT
述語およびFILTER
BY
述語をCDIに含めるか含めないかには、次のヒントを使用できます。
DOMAIN_INDEX_SORT
。問合せオプティマイザは、適用可能なソート条件を、指定したコンポジット・ドメイン索引に含めようとします。
DOMAIN_INDEX_NO_SORT
。問合せオプティマイザは、ソート条件を、指定したコンポジット・ドメイン索引に含めないようにします。
DOMAIN_INDEX_FILTER
(表名索引名)。問合せオプティマイザは、適用可能なFILTER
BY
述語を、指定したコンポジット・ドメイン索引に含めようとします。
DOMAIN_INDEX_NO_FILTER
(表名索引名)。問合せオプティマイザは、適用可能なFILTER
BY
述語を、指定したコンポジット・ドメイン索引に含めないようにします。
例7-1 CDIヒントを使用したテキスト問合せのパフォーマンス・チューニング
次の例では、表books
に対し、最適化された問合せを実行しています。
SELECT bookid, pub_date, source FROM (SELECT /*+ domain_index_sort domain_index_filter(books books_ctxcdi) */ bookid, pub_date, source FROM books WHERE CONTAINS(text, 'aaa',1)>0 AND bookid >= 80 ORDER BY PUB_DATE desc nulls last, SOURCE asc nulls last, score(1) desc) WHERE rownum < 20;
注意: domain_index_filter ヒントは、問合せオプティマイザにCDIの使用を強制しません。かわりに、コストベース・オプティマイザがCDIの使用を選択している場合は、フィルタ述語も索引に含められます。問合せオプティマイザにCDI索引の選択を強制するには、さらにINDEX ヒントも使用する必要があります。 |
Oracle Textには、索引付けおよび問合せ時にボトルネックを識別できる、トレーシング機能があります。
Oracle Textには、事前定義済のトレースのセットが用意されています。各トレースは一意の番号で識別されます。また、この番号に対するCTX_OUTPUT
の記号があります。
各トレースでは、特定の数量を測定します。たとえば、テキスト問合せ時に選択される$I
行の数などです。
トレースは累積カウンタです。そのため、使用方法は次のようになります。
ユーザーがトレースを使用可能にします。
ユーザーが複数の操作を実行します。Oracle Textではアクティビティを測定し、トレースの結果を累積します。
ユーザーがトレース値を取得します。これは、手順2で実行されたすべての操作の合計値となります。
ユーザーがトレースを0(ゼロ)に再設定します。
ユーザーが手順2を繰り返します。
このため、たとえば、手順2でユーザーが2つの問合せを実行し、問合せ1で$I
から15行を選択し、問合せ2で$I
から17行を選択した場合、手順3ではトレースの値は32(15 + 17)となります。
トレースは1つのセッションに関連付けられています。トレースは、1つのセッション内で発生した演算を測定できますが、反対に、複数のセッション間で測定を行うことはできません。
パラレル同期化または最適化中に、トレーシングが現在使用可能である場合のみ、トレース・プロファイルはスレーブ・セッションにコピーされます。各スレーブでは、独自のトレースを累積し、終了前にすべてのトレース値を暗黙的にスレーブ・ログファイルに書き込みます。
一般に、パラレル問合せは、大規模なデータ・コレクションと複数のCPUを備え、同時ユーザー数が少ないDSS、OLAPまたは分析システムに最も適しています。または、Oracle Real Application Clusters(Oracle RAC)ノード間でパラレル化されます。
Oracle Textでは、次のようにパラレル問合せをサポートしています。
パラレル問合せは、ローカルのCONTEXT
索引のパラレル処理を指します。索引の並列度と様々なシステム属性に基づいて、Oracleにより、索引処理のために起動されるパラレル問合せスレーブの数が決定されます。各パラレル問合せスレーブが、1つ以上の索引パーティションを処理します。これは、パラレルに作成されたローカル索引のデフォルトの問合せ動作です。
ただし、同時ユーザー数が多く負荷の高いシステムで問合せが連続的に実行される場合は、通常上位N個のヒットが最初の数個のパーティションによって満たされるため、問合せのスループットはパラレル問合せによって一般に低下します。たとえば、次のような、ORDER
BY
パーティション・キー列を持つ典型的な上位N個のテキスト問合せでは、
select * from ( select story_id from stories_tab where contains(...)>0 order by publication_date desc) where rownum <= 10;
通常、パラレル問合せを使用するとパフォーマンスが下がります。
ALTER INDEX
文を次のように使用して、パラレル索引の操作後にパラレル問合せを使用禁止にできます。
Alter index <text index name> NOPARALLEL; Alter index <text index name> PARALLEL 1;
次のように指定すると、パラレル問合せを使用可能にするか、並列度を上げることができます。
Alter index <text index name> paralllel < parallel degree >;
Oracle Textのパフォーマンスを上げるためにOracle Real Application Clusters(Oracle RAC)を使用するかどうかを考慮する場合、解決しようとしているのがどのパフォーマンス問題であるかを理解することが重要です。Oracle RACは、問合せのスループットを向上するためには非常に有効な解決策です。Oracle Textで問合せの負荷が軽く良好なパフォーマンスが得られる場合は、問合せの負荷が増えた場合、Oracle RACによる優れた拡張性を期待できます。
Oracle RAC環境でのOracle Textでは、テキスト・データおよびテキスト索引を物理的にパーティション化(ローカル・パーティション索引を使用)して、パーティションが個別のOracle RACノードで処理されるようにすることで、パフォーマンスがさらに向上する場合があります。この方法により、複数のノード間でキャッシュ・コンテンツが無駄に重複することが回避されます。その結果、Oracle RACキャッシュ・フュージョンのメリットを最大限活用できます。
Oracle 10g リリース1では、Oracle Textの各索引パーティションは、索引の作成時に個別のデータベース・ファイルに格納される必要があります。これにより、Oracle RACの再マスタリング機能を使用できるようになり、データベース・ファイルのアフィニティが強制されます。各ノードは特定のデータベース・ファイル、つまり特定のOracle Text索引パーティションに集中します。
Oracle 10g リリース2およびそれ以降では、データベース・オブジェクト・レベルのアフィニティがサポートされています。これにより、索引オブジェクト($I
表および$R
表)の特定ノードへの割当てが大幅に容易になっています。
Oracle RACは、問合せのスループットとパフォーマンスを向上させるソリューションを提供していますが、あらゆる場合に効果があるわけではありません。また、データの容量が増えるに従い、同じパフォーマンスの向上を継続的に得られるとはかぎりません。SGAキャッシュに使用できるメモリーの量を増やすか、またはデータをパーティション化することによって、通常は問合せによって表のすべてのパーティションをヒットせずに必要な問合せ結果セットを提供するようにすることで、パフォーマンスが向上する可能性があります。
複数の述語を持つ問合せを発行すると、実行計画でブロック操作が行われる場合があります。たとえば、次の複合問合せについて考えます。
select docid from mytab where contains(text, 'oracle', 1) > 0 AND colA > 5 AND colB > 1 AND colC > 3;
すべての述語が非選択的で、colA、colBおよびcolCがビットマップ索引を持つと想定します。Oracle Databaseのコストベース・オプティマイザでは、次の実行計画を選択します。
TABLE ACCESS BY ROWIDS BITMAP CONVERSION TO ROWIDS BITMAP AND BITMAP INDEX COLA_BMX BITMAP INDEX COLB_BMX BITMAP INDEX COLC_BMX BITMAP CONVERSION FROM ROWIDS SORT ORDER BY DOMAIN INDEX MYINDEX
BITMAP
AND
はブロック操作であるため、Oracle Textでは、BITMAP
AND
操作を実行する前に、Oracle Textのドメイン索引から戻されたROWIDとスコアのペアを一時的に保存する必要があります。
Oracle Textでは、これらのROWIDとスコアのペアをメモリーに保存しようとします。ただし、これらのROWIDとスコアのペアを含む結果セットのサイズがSORT_AREA_SIZE
初期化パラメータの値を超える場合は、Oracle Textにより、これらの結果がディスク上の一時セグメントに排出されます。
ディスクに結果を保存すると余分なオーバーヘッドが発生するため、次のようにALTER
SESSION
を使用してSORT_AREA_SIZE
パラメータを増やすことによって、パフォーマンスが向上します。
alter session set SORT_AREA_SIZE = <new memory size in bytes>;
たとえば、バッファを約8MBに設定するには、次の文を入力します。
alter session set SORT_AREA_SIZE = 8300000;
この項では、問合せのパフォーマンスに関してよくある質問と、それに対する回答を提供します。
回答: 問合せのパフォーマンスは、一般的に次の2つの基準で判断します。
応答時間。個々の問合せに対する応答を取得するまでの時間です。
スループット。任意の時間内に実行可能な問合せの数(たとえば、1秒当たりの問合せ数)です。
この2つは関係していますが、同一ではありません。通常、負荷の高いシステムでは高いスループットが必要ですが、比較的負荷の低いシステムでは応答時間を最短にすることが必要になります。また、アプリケーションによっては、問合せの全ヒットをユーザーに戻すことが必要なものもあれば、順序付けられた結果セットの最初の20ヒットのみを戻すことが必要なものもあります。この2つの状況を区別することが重要です。
回答: 最速タイプの問合せは、次の条件を満たす問合せです。
単一のCONTAINS
句。
WHERE
句内に他の条件がない。
ORDER
BY
句が存在しない。
結果の最初のページのみが戻される(たとえば、最初の10ヒットまたは20ヒット)。
回答: はい。表に関する統計を収集しておくと、Oracle Textがコストベースの分析を実行できます。これにより、問合せに最も効率的な実行計画をOracle Textが選択できます。
回答: テキスト索引がROWIDを戻す速度は、データの実際のサイズには影響されません。テキスト問合せの速度は、索引表からフェッチする必要のある行数、要求されるヒット数、問合せにより生成されるヒット数、およびソートの有無に関係します。
回答: ドキュメントの形式(ASCIIプレーン・テキスト、HTMLまたはMicrosoft Word)は、問合せ速度には影響しません。ドキュメントは、問合せ時ではなく索引付け時にプレーン・テキストにフィルタ処理されます。
データがクリーンであるかどうかが、問合せに影響します。スペルチェック済で編集作業が行われた出版用のテキストは、スペルミスや略語の多い電子メールなどの非公式のテキストと比べて、合計語彙数がかなり少なくなる傾向にあります(したがって、索引表のサイズも小さくなります)。指定した索引メモリー設定では、余分なテキストがあるとメモリー使用量が多くなり、クリーンなテキストと比べて断片化される行が増え、問合せの応答時間に悪影響を及ぼす可能性があります。
回答: カーネルがテキスト索引に対して問合せを行う方法は2つあります。1つ目の方法では、カーネルはテキスト索引に対して特定のテキスト検索を満たすすべてのROWIDを問い合せます。これが最も一般的な方法です。これらのROWIDはまとめて戻されます。2つ目の方法では、カーネルは個々のROWIDをテキスト索引に渡し、その特定のROWIDが特定のテキスト条件を満たすかどうかを問い合せます。
2つ目の方法は機能的検索と呼ばれ、選択性の高い構造化句がある場合に実行されます。このため、テキスト索引に対してチェックが必要なROWIDの数はわずかです。機能的検索が使用される検索の例は、次のとおりです。
SELECT ID, SCORE(1), TEXT FROM MYTABLE
WHERE START_DATE = '21 Oct 1992' <- highly selective AND CONTAINS (TEXT, 'commonword') > 0 <- unselective
構造化列(たとえば、日時や価格など)でORDER BYを行い、テキスト問合せが非選択的な場合にも、機能的検索が使用されます。
回答: すべての問合せで、索引トークン表が参照されます。この表の名前は、DR$indexname$I
の形式です。この表には、トークンのリスト(TOKEN_TEXT
列)とトークンが発生する行とワードの位置に関する情報(TOKEN_INFO
列)が含まれます。
行情報は内部DOCID値として格納されます。この値は外部ROWID値として変換する必要があります。このために使用される表は、検索タイプにより異なります。機能的検索の場合は、$K
表(DR$indexname$K
)が使用されます。これは、DOCIDとROWIDの各ペアに対する行を含む、単純な索引構成表(IOT)です。
索引付き検索の場合は、$R
表(DR$indexname$R
)が使用されます。この表のBLOB列にはROWIDの完全なリストが保持されます。
このため、SQLトレースを調べて$K表または$R表を検索すれば、機能的検索と索引付き検索のどちらが使用されているかが容易に判断できます。
注意: これらの内部索引表は、リリースごとに変更されることがあります。アプリケーションではこれらの表に直接アクセスしないことをお薦めします。 |
回答: はい。低下します。
ソートしない場合、Oracle Textは検索したままの結果を戻すことができます。通常、アプリケーションでは結果を一度に1ページずつ表示するため、この方が高速です。
回答: 関連性スコア(SCORE(n)
)によるソートは、FIRST_ROWS(n)
ヒントを使用すると、非常に高速になります。この場合、Oracle Textはテキスト索引表からフェッチするときに高速の内部ソートを実行します。
このような問合せの例を次に示します。
SELECT /*+ FIRST_ROWS(10) */ ID, SCORE(1), TEXT FROM mytable WHERE CONTAINS (TEXT, 'searchterm', 1) > 0 ORDER BY SCORE(1) DESC;
これを効率的に行うには、1つのCONTAINS
以外の条件をWHERE
句に含めないでください。
回答: 問合せを行うには、大規模なシステム・グローバル領域(SGA)を取得する必要があります。SGA関連のパラメータは、Oracle Database初期化ファイルに設定できます。これらのパラメータは動的に設定することもできます。
SORT_AREA_SIZE
パラメータは、ORDER BY
問合せのソートで使用可能なメモリーを制御します。構造化列で頻繁にORDER BYを行う場合は、このパラメータのサイズを増やす必要があります。
回答: はい。一般に、SELECT
文は元表から複数の列を選択します。Oracle Textでは列をメモリーにフェッチするため、元表のLOBなどの長い列は表外に格納する方が効率的です。これは、その列があまり更新されないが頻繁に選択される場合、特に有効です。
LOBを表外に格納するとき、問合せ中にメモリーにフェッチする必要があるのはLOBロケータのみです。表外に格納すると、元表の有効なサイズが減少し、Oracle Textで表全体をメモリーにキャッシュしやすくなります。これにより、元表から列を選択するコストが低減し、テキスト問合せが高速になります。
さらに、メモリーにキャッシュされる元表が小さくなれば、問合せ中により多くの索引表データをキャッシュできるため、パフォーマンスが向上します。
回答: 最も高速の問合せタイプは、WHERE
句にCONTAINS
句が1つあるのみで、その他の条件が含まれていない問合せです。
複数のCONTAINS
を含む次の問合せについて考えます。
SELECT title, isbn FROM booklist WHERE CONTAINS (title, 'horse') > 0 AND CONTAINS (abstract, 'racing') > 0
セクション検索とWITHIN
演算子を次のように使用すると、同じ結果が得られます。
SELECT title, isbn FROM booklist WHERE CONTAINS (alltext, 'horse WITHIN title AND racing WITHIN abstract')>0
2つ目の問合せの方が高速です。このような問合せを使用するには、索引付けのためにすべてのデータを1つのテキスト列にコピーする必要があります。各列のデータはセクション・タグで囲みます。これは、索引付けの前にPL/SQLプロシージャを使用して実行するか、索引付け時にUSER_DATASTORE
データストアを使用して行い、構造化列とテキスト列を1つのドキュメントに統合します。
回答: 問合せに使用される個別のワードごとに、索引表から少なくとも1行をフェッチする必要があります。このため、拡張の数はできるだけ少なくします。
ワイルド・カード、シソーラス、ステミングおよびファジー・マッチングなどの拡張は、作業上必要でないかぎり、使用しないようにします。一般的に、多少の拡張は許容されますが(たとえば最大20など)、問合せでは100以上の拡張は避けるようにしてください。問合せ式の拡張の数を判断するには、問合せフィードバック・メカニズムを使用できます。
さらに、ワイルド・カードおよびステミングの問合せの場合は、プリフィックス、サブストリングまたはステム索引を作成すると、問合せ時から索引付け時への語句拡張コストをなくすことができます。問合せのパフォーマンスは上がりますが、索引付けの時間が長くなり、ディスク領域が大きくなります。
プリフィックス索引およびサブストリング索引により、ワイルド・カードのパフォーマンスが向上します。プリフィックスとサブストリングの索引付けは、BASIC_WORDLIST
プリファレンスを使用して使用可能にします。次の例では、プリフィックスとサブストリングの索引付けに対してワードリスト・プリファレンスを設定します。プリフィックス索引付けについては、Oracle Textで3〜4文字の長さのトークン・プリフィックスを作成するように指定します。
begin
ctx_ddl.create_preference('mywordlist', 'BASIC_WORDLIST'); ctx_ddl.set_attribute('mywordlist','PREFIX_INDEX','TRUE'); ctx_ddl.set_attribute('mywordlist','PREFIX_MIN_LENGTH', '3'); ctx_ddl.set_attribute('mywordlist','PREFIX_MAX_LENGTH', '4'); ctx_ddl.set_attribute('mywordlist','SUBSTRING_INDEX', 'YES');
end
ステム索引付けは、BASIC_LEXER
プリファレンスを使用して使用可能にします。
begin
ctx_ddl.create_preference('mylex', 'BASIC_LEXER'); ctx_ddl.set_attribute ( 'mylex', 'index_stems', 'ENGLISH');
end;
回答: ローカル・パーティションCONTEXT
索引は、パーティション表に対して作成できます。つまり、パーティション表上では、各パーティションに独自の索引表セットがあることを意味します。実際には複数の索引がありますが、各索引からの結果が必要に応じて組み合され、最終的な結果セットが生成されます。
この索引は、LOCAL
キーワードを使用して作成します。
CREATE INDEX index_name ON table_name (column_name) INDEXTYPE IS ctxsys.context PARAMETERS ('...') LOCAL
パーティション表およびローカル索引を使用すると、次のタイプのCONTAINS
問合せのパフォーマンスが向上します。
これは、パーティション・キー列の特定の値範囲に検索を限定する問合せです。
これは、最初のn個のヒットのみが必要で、ORDER BY
句がパーティション・キーを指定する問合せです。
回答: 場合によります。パラレルに作成された索引の場合にはパラレル問合せがデフォルト動作ですが、通常、負荷の高いシステムでは問合せの全体的なスループットが低下します。
一般に、パラレル問合せは、大規模なデータ・コレクションと複数のCPUを備え、同時ユーザー数が少ないDSSや分析システムに適しています。
回答: テーマ情報にCONTEXT
索引で索引付けすると、時間がかかり、索引のサイズも大きくなります。ただし、テーマ索引を使用すると、ナレッジ・ベースが使用され(使用可能な場合)、ABOUT
問合せの精度が上がります。アプリケーションでABOUT
問合せを頻繁に使用する場合は、索引に対してテーマ・コンポーネントを作成してみる価値はあります。ただし、索引の作成時間と格納領域が余分に必要になります。
回答: CTXCAT
索引は、テキストが小さなチャンク(最大で数行)になっており、特定の構造化基準(通常は数値または日付)に従って、検索で結果セットを制限またはソートする必要がある場合(あるいはその両方)に、最も効率的に機能します。
たとえば、オンラインのオークション・サイトについて考えます。各競売対象品目には、短い説明、現在の入札価格、オークションの開始日と終了日が含まれています。この場合、説明に「antique cabinet」が含まれていて、現在の入札価格が$500未満の全レコードを表示するとします。ユーザーが新しく提示される商品に特に興味がある場合は、結果をオークション開始日でソートする必要があります。
このような検索では、CONTEXT
索引に対してCONTAINS
構造化問合せを使用することは必ずしも効率的ではありません。この問合せでは、構造化句とCONTAINS
句に応じて、応答時間が大きく異なります。これは、構造化句とCONTAINS
句の共通部分またはテキスト問合せの順序付けが問合せ中に計算されるためです。
価格や日付などの構造化情報をCTXCAT
索引内に含めると、検索条件にかかわらず、問合せ応答時間は常に最適な範囲内にとどまります。これは、テキストと構造化問合せ間の相互作用が、索引付け時に事前に計算されるためです。この結果、問合せ応答時間が最適になります。
回答: 索引作成に要する時間と領域に違いがあります。CTXCAT
索引はCONTEXT
索引と比べて作成に時間がかかり、使用するディスク領域もかなり多くなります。ディスク領域に余裕がない場合は、CTXCAT
索引が適切かどうかを慎重に考慮する必要があります。
問合せ演算子に関しては、CATSEARCH
問合せでは問合せテンプレートを使用して、より豊富なCONTEXT
文法を使用できるようになっています。CATSEARCH
問合せ文法のみを使用する必要があるという古い制限はなくなりました。
回答: オプティマイザ・ヒントINDEX(table column)
を通常の方法で使用すると、テキスト索引またはBツリー索引を使用した問合せを実行できます。
NO_INDEX(table column)
ヒントを使用すると、特定の索引を使用禁止にすることもできます。
さらに、テキスト問合せではFIRST_ROWS(n)
ヒントが特殊な意味を持ち、問合せで最初のn個のヒットが必要な場合に使用できます。FIRST_ROWS
ヒントをORDER BY SCORE(n) DESC
とともに使用すると、Oracle Textは、ソート済のセットをテキスト索引から受け入れ、それ以上のソートを実行しないように指示されます。
この項では、索引付けのパフォーマンスに関してよくある質問と、それに対する回答を提供します。
回答: テキストの索引付けは、リソース集中型の処理です。索引付けの速度は関連するハードウェアの性能に依存します。
判断基準としては、平均のドキュメント・サイズが5KBで、次のハードウェア構成とパラレル構成の場合、Oracle Textでは1秒当たり約200のドキュメントに索引を付けることができます。
400MHzのSun Sparc CPU×4
4GBのRAM
EMC symmetrix(24個のストライプ・ディスク)
並列度5(5個のパーティション)
1索引プロセス当たり600MBの索引メモリー
平均5KBのXML形式のニュース・ドキュメント
USER_DATASTORE
ドキュメント形式、データの場所、ユーザー定義データストアのコール、フィルタ、レクサーなどのその他の要因も、索引付けの速度に影響します。
回答: 索引メモリーは、システム・パラメータDEFAULT_INDEX_MEMORY
およびMAX_INDEX_MEMORY
を使用して設定できます。また、CREATE INDEX
のパラメータ文字列にmemory
パラメータを指定して、索引メモリーを実行時に設定することもできます。
DEFAULT_INDEX_MEMORY
値は、ページングが発生しない範囲で、できるだけ高く設定するようにします。
SORT_AREA_SIZE
システム・パラメータを増やして、索引付けのパフォーマンスを向上させることもできます。
経験則では、索引メモリー設定を大きくすると(数百MB程度)、索引付けの速度が上がり、最終的な索引の断片化が減少します。ただし、高く設定しすぎると、メモリーのページングが発生し、索引付けの速度が低下します。
索引のパラレル作成では、各プロセスがそれぞれ索引付け用のメモリーを必要とします。巨大な表を扱う場合には、索引作成時と検索時とで、システム・グローバル領域(SGA)のチューニング方法を変えます。問合せでは、システム・グローバル領域(SGA)のブロック・バッファ・キャッシュにできるだけ多くの情報をキャッシュするようにします。このため、ブロック・バッファ・キャッシュには大量のメモリーを割り当てる必要があります。ただし、この設定は索引付けには影響を与えないため、索引作成時には、SGAのサイズを減らして、索引付け処理中の索引メモリー設定を大きくする方が賢明です。
SGAのサイズはOracle Database初期化ファイルで設定します。
回答: オーバーヘッド(索引表に必要な領域の量)は、元のテキスト量の50%から200%まで様々です。一般に、テキストの総量が多ければ多いほどオーバーヘッドは小さくなりますが、多数の小さなレコードの方が、少数の大きなレコードよりもオーバーヘッドの消費が大きくなります。また、クリーンなデータ(出版済のテキストなど)は、電子メールや討論記録などの未処理のデータと比べて、必要なオーバーヘッドは小さくてすみます。これは、未処理のデータにはスペルミスや略語などの特異なワードが数多く含まれている可能性が高いためです。
テキストのみの索引は、テキストとテーマを組み合せた索引よりも小さくなります。プリフィックス索引およびサブストリング索引では、索引がかなり大きくなります。
回答: Microsoft Wordファイルなどの書式化されたドキュメントの場合は、ドキュメント内に含まれている実際のテキストに比べてドキュメント・サイズが大きくなる傾向にあるため、記憶域オーバーヘッドはファイル・サイズに比べてかなり低くてすみます。1GBのWordドキュメントに必要な索引領域は50MBのみであるのに対して、1GBのプレーン・テキストの場合は500MB必要になることがあります。これは、後者のファイルには前者よりも10倍のプレーン・テキストが含まれている可能性があるためです。
索引付けに要する時間については、これほど単純ではありません。索引付け対象のテキスト量が減れば明らかな影響は出ますが、索引付けに要する時間を見積るためには、AUTO_FILTER
フィルタまたはその他のユーザー定義フィルタを使用してドキュメントをフィルタ処理する時間を相殺することが必要になります。
回答: データが大量にあり、CPUも複数ある場合は、パラレル索引付けにより、索引付けのパフォーマンスが向上します。
索引を作成するときに、次のようにPARALLEL
キーワードを使用します。
CREATE INDEX index_name ON table_name (column_name) INDEXTYPE IS ctxsys.context PARAMETERS ('...') PARALLEL 3;
これで、リソースに応じて最大3つの索引付けプロセスを使用して索引が作成されます。
また、パラレル索引付けを使用して、パーティション表のローカル・パーティション索引を作成することもできます。ただし、CPUが複数あるときのみ、索引付けのパフォーマンスは向上します。
注意: ローカル・パーティション索引を作成するのに PARALLEL を使用すると、パラレル問合せが有効になります。(非パーティション索引をパラレルに作成しても、問合せはパラレルに処理されません。)
パラレル問合せにより、特に負荷の高いシステムでは、問合せのスループットが低下します。このため、パラレル索引作成後はパラレル問合せを使用禁止にすることをお薦めします。この場合は、 |
回答: CPUが複数あるときは、ローカル索引をパラレルで作成することで索引付けのパフォーマンスを改善できます。索引付けをパラレルで行うには、次の2つの方法があります。
ローカル・パーティション索引をパラレルで作成するには、次の2つの方法があります。
CREATE_INDEX
で、LOCAL
句とともにPARALLEL
句を使用します。この場合、最大並列度はユーザーが持つパーティションの数によって制限されます。
使用禁止の索引を最初に作成し、次にDBMS_PCLXUTIL.BUILD_PART_INDEX
ユーティリティを実行します。このメソッドを使用すると、特にパーティション数以上のCPUがある場合に、並列度が高くなります。
次に、2番目のメソッドの例を示します。次の例では、元表にパーティションが3つあります。使用禁止のローカル・パーティション索引を最初に作成してから、DBMS_PCLUTIL.BUILD_PART_INDEX
ユーティリティを実行します。このユーティリティにより、3つのパーティションがパラレルに作成されます(パーティション間並列性)。また、各パーティション内では、索引の作成が並列度2によりパラレルに実行されます(パーティション内並列性)。
create index tdrbip02bx on tdrbip02b(text) indextype is ctxsys.context local (partition tdrbip02bx1, partition tdrbip02bx2, partition tdrbip02bx3) unusable; exec dbms_pclxutil.build_part_index(3,2,'TDRBIP02B','TDRBIP02BX',TRUE);
この項では、索引の更新と関連するパフォーマンスの問題に関してよくある質問と、それに対する回答を提供します。
回答: CTX_DLL.SYNC_INDEX
を使用して再索引付けを実行する頻度が低いほど、索引の断片化が少なくなり、索引の最適化を実行する頻度も低く抑えることができます。
ただし、これではデータが次第に古くなるため、ユーザーにとっては不便になる可能性があります。
ほとんどのシステムでは、毎日の夜間の索引付けで十分です。つまり、作成されてから1日未満のデータは検索できないということです。毎時、10分ごとまたは5分ごとに更新を行うシステムもあります。