2017-05-30 15 views
0

最初にワイルドカードを使用してLIKEを使用してクエリを実行するSQL Serverのデータベースモデルを最適化する方法を知りたいと思います。私はDBのエキスパートではないので、インデックスやその他の最適化の使用に関するアドバイスは大歓迎です。ワイルドカードを使用した高速LIKEクエリのDBモデルの最適化方法

状況:この表は300000+レコードが含ま

ShortNameEN (varchar(50)) 
ShortNameFR (varchar(50)) 
ShortNameDE (varchar(50)) 
ShortNameNL (varchar(50)) 
LongNameEN (varchar(250)) 
LongNameFR (varchar(250)) 
LongNameDE (varchar(250)) 
LongNameNL (varchar(250)) 

私は、次の列を持つテーブル '製品' を持っています。

にはの検索文字列(ShortNameENでのみ)が含まれているレコードを見つけるためにselect文を書く必要があります。 私のクエリは

SELECT * 
FROM Products 
WHERE ShortNameEN LIKE '%searchstring%' 

です。もちろん、このクエリは非常に遅いです。 ShortNameENにインデックスを追加することは、最初のワイルドカードのために使用されないため、役に立たない。

質問1: ShortNameEN列を他の表と分けるのは意味がありますか?私は、ディスクアクセス/行サイズ/ページサイズと、これがパフォーマンスにどのように影響するかについて全く知らない。おそらく、ここでパフォーマンスを向上させることができる他のファイルシステム関連の最適化がありますか?

一時的な解決策は、私は創造的な「トライグラム」ソリューションを見つけましたが、私のモデルにかなりの影響を与えます。このために私は私の最初のテーブルを参照する第二表「ProductNameFragments」を作成し、すべてのShortNameEN、次のようにブレークダウン:のProductId = 123、ShortNameEN =「プリンタ」

ProductId | NameFragment 
123  | PRINTER 
123  | RINTER 
123  | INTER 
123  | NTER 
123  | TER 
123  | ER 
123  | R 

トリガーのため

例ProductテーブルはProductNameFragmentsテーブルを同期します。

このようにして、2つのテーブルに参加し、最初のワイルドカードなしでクエリできます。

SELECT p.* 
FROM Product p, ProductNameFragment pnf 
WHERE p.Id = pnf.ProductId 
AND pnf.NameFragment LIKE '%searchstring%' 

最初のテストでは、検索クエリのパフォーマンスが大幅に向上することがわかりました。

質問2:通常のインデックスまたはProductNameFragmentのクラスタードインデックスを使用します製品の更新/削除/挿入時のパフォーマンスへの影響はどのようになりますか? 1つの製品名を更新すると、ProductNameFragmentsテーブルに50の削除と50の挿入が発生する可能性があります。インデックスを強制的に更新することはできますか?

最後に、私は複雑さのために、「トリグラム」ソリューションを使用しないことをお勧めします。だから、ヒントやトリックは歓迎以上のものです。予め

Thxを

スティーブン一般

+2

フルテキスト検索:https://docs.microsoft.com/en-us/sql/relational-databases/search/full-text-searchから始めます。 –

+1

今日のヒント:現代的で明示的な 'JOIN'構文に切り替えます。書き込みが簡単(エラーなし)、読みやすく保守が容易、必要に応じて外部結合に変換する方が簡単です。 – jarlh

+2

フルテキスト検索を使用することをお勧めします。https://docs.microsoft.com/en-us/sql/relational-databases/search/full-text-search –

答えて

1

、全文検索(FTS)の主な目的は、次のとおり

  1. はプリ/サフィックス、変曲点を破棄、(ルートによる検索をステミング、等)について、特定の言語に関して、
  2. バイナリ形式(DOC/X、PDFなどのファイル形式のテキストなど)の索引付け。

Microsoft SQL Serverに同梱されているFTSエンジンには、ワイルドカード検索がありませんので、気にしないでください。

あなたが言いました解決策は、AFAIKです。これは、あなたにワイルドカードをリードするためのまともなパフォーマンスを与える唯一のものです。さらに、この種の機能性を主張するFTS製品は、カーテンの後ろにこの非常に「トリグラム」アルゴリズムを実装します。

独自の実装のために、このような表は、良いスタートになります:

create table dbo.TextFragments (
    TextFragment nvarchar(...) not null, -- Maximum size depends on your data 
    LanguageId int not null, 
    EntityId int not null, 
    RowId bigint not null, 
    constraint [PK_TextFragments] primary key (TextFragment, LanguageId, EntityId, RowId) 
); 

私は、単一のテーブルに一緒にすべての言語を入れています。それがなければ、あなたのシステムに新しい言語を追加することはむしろ複雑になるでしょう。もちろん、言語ルックアップテーブルも必要です。

EntityIdフィールドでは、異なるテーブルのデータにインデックスを付けることができます。正確に1つのテーブルがあり、他にインデックスを作成する予定がない場合は、フィールドを削除できます。

フィールドは、フラグメントに一致する対応するテーブル内の行の識別子を格納します。もちろん、データ型を調整したり、他の列を追加したりしてシステムで動作させることができます。

他の人にも示唆されているように、照合とテキスト断片の囲みを使って検索をさらに最適化することができます。将来、システムがより多くのエントリ(たとえば100M)を格納する場合、パーティション分割を導入して、単一のセクションのサイズを妥当な範囲内に保つことが必要な場合があります。今はピーナッツだから、それやファイルシステムの問題は心配しないでください。

+0

Thxです。確かに、私はすでにFTSについて言及していませんでした。私の質問の目的は、インデックスに関するヒントやテクニック、そしてSQL Serverのfinetuningのためのファイルシステムの最適化を受けることでした。 – StevenQ

+0

@StevenQ、答えを更新しました。 –

2

フルテキスト検索を行わない場合は、フルインデックススキャンが必要です。ワイルドカードスキャンのパフォーマンスを最適化するためにできる唯一の方法は、Windows照合の代わりに従来のSQL_ *照合を使用することです。従来の照合では、単純ではありませんが、堅牢性は低いものの、比較ルールによってオーバーヘッドが少なくなっています。

ProductFragmentテーブルProductIDカラムにクラスタードインデックスを指定して、製品レベルの操作を最適化することをお勧めします。あるいは、ProductIDNameFragmentナチュラルキーのクラスタ化された主キーは、挿入/更新/削除操作を最適化し、データの整合性を保証します。

+0

この時点で、バイナリ照合を使用すると、さらに多くのスピードが得られます。 – sepupic

+0

@StevenQ、バイナリ照合が最速になることに同意しました。大文字小文字を区別しないバイナリ照合による検索が必要な場合は、一貫性のあるケース(サンプルデータのように上部)に名前フラグメントを格納し、同じ場合に検索文字列を指定する必要があります。 –

関連する問題