使用IEqualityComparer优化LINQ查询性能

3

我正在使用IEqualityComparer在使用LINQ to Entities的数据库中匹配“近似重复项”。

在大约40,000条记录集的情况下,此查询需要约15秒才能完成,我想知道是否可以对以下代码进行任何结构上的更改。

我的公共方法

public List<LeadGridViewModel> AllHighlightingDuplicates(int company)
        {

            var results = AllLeads(company)
                  .GroupBy(c => c, new CompanyNameIgnoringSpaces())
                  .Select(g => new LeadGridViewModel
                  {
                      LeadId = g.First().LeadId,
                      Qty = g.Count(),
                      CompanyName = g.Key.CompanyName
                  }).OrderByDescending(x => x.Qty).ToList();

            return results;

        }

获取潜在客户的私有方法

private char[] delimiters = new[] { ' ', '-', '*', '&', '!' };
private IEnumerable<LeadGridViewModel> AllLeads(int company)
        {
            var items = (from t1 in db.Leads
                          where
                              t1.Company_ID == company
                          select new LeadGridViewModel
                          {
                              LeadId = t1.Lead_ID,
                              CompanyName = t1.Company_Name,
                          }).ToList();


            foreach (var x in items)
                x.CompanyNameStripped = string.Join("", (x.CompanyName ?? String.Empty).Split(delimiters));

            return items;
        }

My IEqualityComparer

 public class CompanyNameIgnoringSpaces : IEqualityComparer<LeadGridViewModel>
    {
        public bool Equals(LeadGridViewModel x, LeadGridViewModel y)
        {
            var delimiters = new[] {' ', '-', '*', '&', '!'};
            return delimiters.Aggregate(x.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '\0')) 
                == delimiters.Aggregate(y.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '\0'));
        }

        public int GetHashCode(LeadGridViewModel obj)
        {
            var delimiters = new[] {' ', '-', '*', '&', '!'};
            return delimiters.Aggregate(obj.CompanyName ?? String.Empty, (c1, c2) => c1.Replace(c2, '\0')).GetHashCode();
        }
    }

我会把定界符数组设置为静态只读的,但我怀疑这对性能的提升不会太大。 - Adam Houldsworth
是的,你确实应该尽可能地在数据库端完成这项工作,而不是全部在内存中完成。很可能那样会变得更快。 - Servy
2个回答

2
你可以使用 Regex.Replace 一次性完成所有的替换:
public class CompanyNameIgnoringSpaces : IEqualityComparer<LeadGridViewModel>
{
    static Regex replacer = new Regex("[ -*&!]");
    public bool Equals(LeadGridViewModel x, LeadGridViewModel y)
    {
        return replacer.Replace(x.CompanyName, "")
            == replacer.Replace(y.CompanyName, "");
    }

    public int GetHashCode(LeadGridViewModel obj)
    {
        return replacer.Replace(obj.CompanyName, "").GetHashCode();
    }
}

那样做可能会更快,试一下吧!(还要注意我跳过了空值检查,你可能需要以某种方式把它们放回去。)

1
可以通过编译正则表达式(使用“RegexOptions.Compiled”)来略微改进此代码。 - Paolo Moretti

2

一种方法是在数据库上创建一个计算列,该列是不需要的字符去除后的公司名称。

然后使用此列进行筛选。

这可能会略微降低插入操作的性能,但应该会极大地提高查询时间。


这是一个很好的建议。你会推荐为此编写一个函数吗? - Nick
是的,这里有一种可以适应的东西... http://davidbridge.wordpress.com/2011/04/11/sql-server-alltrim/ - Justin Harvey
没问题,请告诉我你得到了什么性能提升。 - Justin Harvey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接