21

私は2列の大きなテーブルを持っています:IdとTitle。 Idはbigintで、タイトル列のタイプを自由に選ぶことができます:varchar、char、text、何でも。列タイトルには、最大255文字の "abcdefg"、 "q"、 "allyourbasebelongtous"のようなランダムな文字列が含まれています。SQLで部分文字列を検索する最速の方法は?

私の仕事は、指定された部分文字列で文字列を取得することです。部分文字列もランダムな長さを持ち、文字列の開始、途中、または終わりにすることができます。

SELECT * FROM t LIKE '%abc%' 

私はINSERTについて気にしません。私は高速選択を行うだけでよいのです。できるだけ早く検索を実行するにはどうすればよいですか?

私はMS SQL Server 2008 R2を使用していますが、私が見ている限り、フルテキスト検索は役に立たなくなります。

+11

信じられないほど貧弱なデータベースパフォーマンスの素晴らしい世界へようこそ: – paxdiablo

+8

全文検索はなぜ役に立たないのですか? –

+0

サブ文字列をトークンにすることはできますか?スペース、コンマ、またはハイフンで単語を分割できる場合は、私は考えがあります。お知らせ下さい。 – sgtz

答えて

8

ランディの答えよりも少ないスペースを使い、データにかなりの反復がある場合は、各エッジが次の文字であるN-Aryツリーデータ構造を作成し、その上に。

ノードの深さを最初に指定します。レコードのIDと、文字列または末尾の部分文字列と一致するツリーのノードIDを使用して、レコードごとに最大255行のテーブルを作成できます。次に、検索を実行すると、検索する文字列(およびすべての末尾の部分文字列)を表すノードIDが検索され、範囲の検索が実行されます。

+0

ありがとう、私は今あなたとランディの解決策を試すことができませんが、私はできるだけ早く試してみます。 – msergey

4

あなたはすべての良い選択肢を排除したように思えます。

あなたはすでにあなたのクエリ

SELECT * FROM t WHERE TITLE LIKE '%abc%' 

がインデックスを使用しません、それはすべての時間をスキャン全表を行いますことを知っています。

あなたは、文字列フィールドの開始であったと確信していた場合は、タイトルの上にインデックスを使用することになり

SELECT * FROM t WHERE TITLE LIKE 'abc%' 

を行うことができます。

ここで全文検索をお勧めしますか?インデックスを使用しますこれは、最初のクエリ(LIKE 'abc%')「で始まる」

  • を行います

    は、ビジネス要件に応じて、私は時々、次のロジックを使用しました。

  • 任意の行が返された場合によっては
  • (または何)、条件付きでフルスキャンを行います「難しい」の検索に移動(LIKE '%abc%'

はもちろん、あなたが必要なものに依存しますが、私はこれを、最も簡単で最も一般的な結果を最初に表示し、必要なときにはより困難なクエリに移ることができるような状況で使用しました。

+0

タイトルの途中にある可能性が高いサブストリングがありますが、私はあなたのアプローチでパフォーマンスを測定しようとします。 – msergey

+0

またはクラスタ化インデックススキャン。おそらく大きな違いはありません。 – JeffO

+0

@Jeff - それは単なる意味論です。クラスタ化インデックススキャンは、クラスタ化インデックスを持つテーブルの "フルテーブルスキャン"です(大部分のテーブルはこれですべきです)。いずれにしても、すべてのレコードを読み取る必要があります。 – BradC

13

ストレージを気にしない場合、各部分文字列(通常のタイトルあたり最大255個のエントリ)から始まる部分的なタイトルエントリを持つ別のテーブルを作成できます。

このように、これらの部分文字列を索引付けし、文字列の先頭にのみ一致させると、パフォーマンスが大幅に向上します。

+1

このテーブルをクラスタ化された一意ではないインデックスにする...これはおそらく、生のSQLを取得するのと同じくらい良いことです。 – sgtz

3

テーブルに別の計算カラムを追加することもできます。titleLength as len(title)PERSISTED。これは、 "タイトル"列の長さを格納します。この上にインデックスを作成します。

また、ReverseTitleをReverse(タイトル)PERSISTEDという別の計算列を追加します。

誰かがキーワードを検索するとき、キーワードの長さがtitlelengthと同じであるかどうかを確認します。もしそうなら、 "="検索を行います。キーワードの長さがtitleLengthの長さより短い場合は、LIKEを実行します。しかしまずタイトルをLIKE 'abc%'にしてからreverseTitle LIKE 'cba%'を実行します。 Bradのアプローチと同様です。つまり、必要な場合にのみ次の難しいクエリを実行します。

また、80-20のルールがキーワード/部分文字列に適用される場合(つまり、ほとんどの検索がキーワードの少数しかない場合)、何らかのキャッシュを行うことを検討することもできます。たとえば、多くのユーザーがキーワード "abc"を検索し、このキーワード検索でids 20、22、24、25のレコードが返されたとします。これを別のテーブルに格納し、これを索引付けすることができます。 そして誰かが新しいキーワードを検索したとき、最初にこの「キャッシュ」テーブルを調べて、検索が以前のユーザーによってすでに実行されていたかどうかを確認します。もしそうなら、メインテーブルを再度見る必要はありません。単に「キャッシュ」テーブルの結果を返します。

上記をSQL Server TextSearchと組み合わせることもできます。 (あなたがそれを使用しない正当な理由があると仮定して)。それにもかかわらず、最初にテキスト検索を使用して結果セットの候補リストを作成できます。テーブルに対してSQLクエリを実行して、TExt Searchによってキーワードとともにパラメータとして返されたIDを使用して正確な結果を得ることができます。

これは明らかにSQLを使用する必要があることを前提としています。もしそうでなければ、Apache Solrのようなものを探索することができます。

0

インデックスビューを作成するsql create indexに新しい機能が追加されました。検索でそのビューを検索して使用すると、より高速な結果が得られます。 クラスタ化インデックス文字列と

0
  1. 使用ASCII文字セット。 ラムとディスクの両方にデータ のサイズがあるため、文字セットは検索パフォーマンスに影響します。ボトルネックは多くの場合I/Oです。
  2. あなたのカラムは255文字ですので、通常のインデックスを のフルテキストではなくcharフィールドで使用することができます。これは高速です。 のselect文で不要な列を選択しないでください。
  3. 最後に、サーバーにRAMを追加し、キャッシュサイズをに増やしてください。
+0

私は、他の返信陽気なN - アリーツリーメソッドを見つける。 –

+2

なぜそれは陽気ですか? –

0

特定の列にプライマリキーを使用してください。&クラスタ形式でインデックスを作成してください。

次に任意の方法(ワイルドカードまたは=、または任意)を使用して検索テーブルをクラスタ化された形式で既にあるので、(列がソートされた形で、すでにあるので)それは彼が見つけることができる場所を知っているので、それが最適な検索します

関連する問題