繁体   English   中英

针对强类型数据集的慢LINQ查询

[英]Slow LINQ query against strongly typed Dataset

我有一个包含约5,000行的数据库。 还有许多多对多的关系。 我需要跨表进行自由文本搜索,作为“高级搜索”查询的一部分。

我创建了一个强类型的数据集,并在应用启动时从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
      };

一些想法:

首先,您要搜索字符串。 如果要搜索的内容很多,请考虑维护全文索引以加快搜索速度。

其次,将where子句放在join子句之前。 过滤数据的内容在LINQ语句中应尽可能高。 它当前正在为每一行加入一堆数据,即使where子句为false也不使用它。

假设您仍然加载到DataSet而不是对象列表中(没有足够的信息来翻译该部分),这是我的建议:

预加入要用作搜索索引的数据:

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
          };

顺便说一句,您的示例代码没有任何理由进行联接,因为没有联接范围变量在条件或答案中使用,并且无论如何您都将每个联接都联接在一起,因此,将它们排除在外将是最快的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM