1

Oracle 11GR2 には、160 万を超えるレコードを含むテーブルに単純な検索ストア プロシージャがあります。「%boston%」などの列内の作品を検索したい場合、12 秒かかるという事実に困惑しています。名前の列に索引があります。

select description from travel_websites where name like "%boston%";

「boston%」のようにボストンで始まる単語だけを検索すると、0.15 秒しかかかりません。

select description from travel_websites where name like "boston%";

インデックス ヒントを追加し、オプティマイザーに name 列のインデックスを強制的に使用させようとしましたが、どちらも役に立ちませんでした。

select description /*+ index name_idx */  from travel_websites where name like "%boston%";

アドバイスをいただければ幸いです。

4

2 に答える 2

6

先行するワイルドカード (つまり ) を持つ述語に対してインデックス範囲スキャンを使用することはできませんlike '%boston%'。インデックスがディスクにどのように格納されているかを考えれば、これは理にかなっています。検索している文字列の最初の文字がわからない場合、インデックスを走査してその文字列に一致するインデックス エントリを探すことはできません。 . すべてのリーフブロックを読み取るインデックスの完全なスキャンを実行し、nameそこを検索して、必要な文字列が含まれているかどうかを確認できる場合があります。ただし、それにはインデックスの完全なスキャンが必要であり、さらに毎回テーブルにアクセスする必要がありますROWIDフルスキャンしたばかりのインデックスの一部ではない列を取得するために、インデックスから取得します。テーブルとインデックスの相対的なサイズ、および述語の選択性に応じて、先頭のワイルドカードを検索している場合、オプティマイザーはテーブル スキャンを実行する方が速いと簡単に判断できます。

Oracle は全文検索をサポートしていますが、Oracle Text を使用する必要があります。これには、name列に Oracle Text インデックスを作成し、問合せではなくCONTAINS 演算子LIKEを使用して検索を行う必要があります。Oracle Text は非常に堅牢な製品であるため、どの程度高度なものを取得するかに応じて、索引の作成、索引の更新、​​および問合せの作成の両方で考慮すべきオプションが多数あります。

インデックス ヒントが正しく指定されていません。にインデックスnameがあり、そのインデックスの名前が であり、インデックスname_idxのフル スキャンを強制したいとします (繰り返しますが、先頭にワイルドカードがある場合、インデックスの範囲スキャンは有効なオプションではありません)。 、次のようなものが必要です

select /*+ index(travel_websites name_idx) */ description
  from travel_websites
 where name like '%boston%'

ただし、完全なインデックス スキャンが完全なテーブル スキャンよりも効率的であるという保証はありません。また、オプティマイザーが既にヒントなしでインデックス フル スキャンを選択している可能性は十分にあります (3 つのクエリのクエリ プランを指定しません)。

于 2012-08-29T21:03:50.040 に答える
2

Oracle(および私が知る限り、他のほとんどのデータベース)はデフォルトで文字列にインデックスを付けるため、インデックスは文字列の先頭から文字列の一致を検索するためにのみ使用できます。つまり、LIKE 'boston%'(startswith) はインデックスを使用できますが、LIKE '%boston'(endswith) またはLIKE '%boston%'(contains) は使用できません。

部分文字列をすばやく見つけることができるインデックスが本当に必要な場合は、文字列に通常のインデックス タイプを使用することはできませんが、TEXT悲しいことにわずかに異なるクエリ構文が必要になる可能性があるインデックスを使用することはできます。

于 2012-08-29T21:08:35.410 に答える