2017-10-18 55 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优化和统计信息收集/查询计划选择。例如。我想有* *没有*机会执行索引搜索'索引搜索',SQL Server-LINQ可以(通过string.Contains)。 – user2864740

+0

LINQ将连接转换为查找表,因此尽管您所做的工作量相对较高,但它仍应该快速。如果这很慢,那几乎肯定与使用数据集有关。 –

+2

不是将数据加载到DataSet中,而是使用查询动态加入,请考虑使用POCO(仅创建一个类)并在加载时预先执行'join',因此您不必每次查询时创建查找表。您可能还想考虑将其切换到代码复审。 – NetMage

回答

1

假设你仍然加载到DataSet 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 
      }; 

顺便说一句,你的示例代码显示没有理由这样做的加入为none联办范围内的变量在条件或答案中使用,而且无论如何你都要加入每一个变量,所以把它们排除在外是最快的解决方案。

1

的几点思考:

首先,你要搜索的字符串。如果搜索量很大,请考虑维护全文索引以加快速度。

二,将where子句放在join子句之前。过滤掉数据的东西在LINQ语句中应该尽可能地高。它目前正在加入每一行的一堆数据,即使在where子句为假的情况下也不会被使用。