2017-10-18 5 views
0

私は約5,000行のデータベースを持っています。多対多の関係も多数あります。私は、 "高度な検索"クエリの一環としてテーブル間でフリーテキスト検索を行う必要があります。強く型付けされたデータセットに対してLINQクエリが遅い

私は強く型付けされたデータセットを作成し、アプリケーションの起動時にSQL Serverからすべてのデータをインポートしました。データセットに対してLINQクエリを実行すると、クエリは非常にゆっくり実行されます(約15秒)。メモリ内のデータセットに対してクエリを実行するとSQL Serverよりもはるかに高速になると考えられましたが、そうは思われません。私はさらにwhere節に結合と "検索"を追加する必要があるので、事態が悪化するだけです。

私が検索しているフィールドでは、最長が「要約」で、データベースの中で最長のものが2,000バイト未満であるため、検索するデータがたくさんあるわけではありません。私は間違ったツリーをここで吠えているのですか、またはこのクエリのパフォーマンスを向上させる手段がありますか?

var results = from e in _data.ds.Employee 
     join es in _data.ds.EmployeeSkill on e.EmployeeId equals es.EmployeeId into esGroup from esItem in esGroup.DefaultIfEmpty() 
     join s in _data.ds.Skill on esItem?.SkillId equals s.SkillId into sGroup from skillItem in sGroup.DefaultIfEmpty() 
     join er in _data.ds.EmployeeRole on e.EmployeeId equals er.EmployeeId into erGroup from erItem in erGroup.DefaultIfEmpty() 
     join r in _data.ds.Role on erItem?.RoleId equals r.RoleId into rGroup from rItem in rGroup.DefaultIfEmpty() 
     join et in _data.ds.EmployeeTechnology on e.EmployeeId equals et.EmployeeId into etGroup from etItem in etGroup.DefaultIfEmpty() 
     join t in _data.ds.Technology on etItem?.TechnologyId equals t.TechnologyId into tGroup from tItem in etGroup.DefaultIfEmpty() 
     where 
     e.FirstName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     e.LastName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     e.RMMarket.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     !e.IsSummaryNull() && e.Summary.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 
     select new SearchResult 
     { 
      EmployeeId = e.EmployeeId, 
      Name = e.FirstName + " " + e.LastName, 
      Title = e.Title, 
      ImageUrl = e.IsImageUrlNull() ? string.Empty : e.ImageUrl, 
      Market = e.RMMarket, 
      Group = e.Group, 
      Summary = e.IsSummaryNull() ? string.Empty : e.Summary.Substring(1, e.Summary.Length < summaryLength ? e.Summary.Length - 1 : summaryLength), 
      AdUserName = e.AdUserName 
     }; 
+2

"インメモリ" LINQは、長年のRA/SQL最適化と統計収集/クエリプランの選択の恩恵を受けません。例えば。私はIndexOf上で「インデックスシーク」を実行する機会がないと考えています。これはSQL Server-LINQが(string.Containsを介して)行うことができます。 – user2864740

+0

LINQはジョインをルックアップテーブルに変換するので、作業量が比較的多いにもかかわらず、まだ高速であるはずです。これが遅い場合、データセットを使用することとほぼ確実に関係します。 –

+2

データを 'DataSet'sにロードしたり、クエリと動的に' join'するのではなく、POCO(クラスを作成するだけです)を使用してロード時に 'join'を事前実行することを検討してください。照会するたびにルックアップ・テーブルを作成します。これをCode Reviewに切り替えることを検討することもできます。 – NetMage

答えて

1

ではなく、オブジェクトのリスト(その部分を翻訳しないように十分な情報)のS-、ここで私がお勧めです:

プリジョイン・データが検索インデックスとして使用する:

var searchBase = (from e in _data.ds.Employee 
      join es in _data.ds.EmployeeSkill on e.EmployeeId equals es.EmployeeId into esGroup 
      from esItem in esGroup.DefaultIfEmpty() 
      join s in _data.ds.Skill on esItem?.SkillId equals s.SkillId into sGroup 
      from skillItem in sGroup.DefaultIfEmpty() 
      join er in _data.ds.EmployeeRole on e.EmployeeId equals er.EmployeeId into erGroup 
      from erItem in erGroup.DefaultIfEmpty() 
      join r in _data.ds.Role on erItem?.RoleId equals r.RoleId into rGroup 
      from rItem in rGroup.DefaultIfEmpty() 
      join et in _data.ds.EmployeeTechnology on e.EmployeeId equals et.EmployeeId into etGroup 
      from etItem in etGroup.DefaultIfEmpty() 
      join t in _data.ds.Technology on etItem?.TechnologyId equals t.TechnologyId into tGroup 
      from tItem in etGroup.DefaultIfEmpty() 
      select new { 
       e.FirstName, e.LastName, e.RMMarket, e.Summary, 
       e.EmployeeID, e.Title, e.ImageUrl, e.Group, e.AdUserName 
      }).ToList(); 

がロードに対して検索を実行し、データ加わっ:ところで

var results = from e in searchBase 
      where 
       e.FirstName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       e.LastName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       e.RMMarket.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       !e.IsSummaryNull() && e.Summary.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 
      select new SearchResult { 
       EmployeeId = e.EmployeeId, 
       Name = e.FirstName + " " + e.LastName, 
       Title = e.Title, 
       ImageUrl = e.IsImageUrlNull() ? string.Empty : e.ImageUrl, 
       Market = e.RMMarket, 
       Group = e.Group, 
       Summary = e.IsSummaryNull() ? string.Empty : e.Summary.Substring(1, e.Summary.Length < summaryLength ? e.Summary.Length - 1 : summaryLength), 
       AdUserName = e.AdUserName 
      }; 

を、あなたのサンプルコードは、城のどれも加わり行うには理由を示しません範囲変数は条件や答えに使用されているので、あなたはそれぞれの変数に結びついているので、それらを放置するだけで最速の解決策になります。

1

いくつかの考え:

まず、あなたが検索している文字列

は、ここでは、コードです。検索する数が多い場合は、フルテキストインデックスを維持してスピードアップしてください。

第2に、join句の前にwhere句を挿入します。データをフィルタリングするものは、できるだけLINQステートメントで最高になるはずです。現在のところ、すべての行のデータには、where句がfalseの場合には使用されない場合もあります。それでもDataSetに読み込むと仮定すると、

関連する問題