在 Linq 中使用多个包含需要时间来加载性能问题

Posted

技术标签:

【中文标题】在 Linq 中使用多个包含需要时间来加载性能问题【英文标题】:Using multiple Contains taking time to load performance issue in Linq 【发布时间】:2019-10-26 20:48:27 【问题描述】:

我在一个表中有超过 600,000 条记录和 20 列。

我想使用一个 LINQ 查询并使用一个用作“LIKE”的函数;所以为此我使用了Contains。它需要时间(或)它会引发超时过期异常。

那么任何人都可以建议如何解决这个问题?我需要比较超过 4 列。

var majorAgents = new[]  "iPhone", "android", "iPad" ;


List<Person> lstperson =_context.person.where 
                      (w=>majorAgents.Any(x=>w.personLastName.contains(x))
                      || majorAgents.Any(x=>w.personFirstName.contains(x))
                      ||w.Address.Any(s=>majorAgents.Contains(s.addressProof)))//Address table referenced as a list 
                        .select(s=> new Person
                             s.personId,
                             s.perosnLastName,
                             s.personFirstName
                    ).ToList();

【问题讨论】:

我建议从表中选择整个数据并在那里执行包含。它可能会更快。另外,尝试通过编写 SQL 存储过程并从 EF 调用它来检查这一点(我相信你正在使用它) 如果性能非常重要,也许您可​​以在另一列中预先计算出您要查找的值。 AFAIK 在 SQL 查询中使用OR 存在性能问题,我可以建议删除那些||,例如:where(w=&gt;majorAgents.Any(x=&gt;$"w.personLastName|@|w.personFirstName".contains(x))) ;)。 【参考方案1】:

也许您应该尝试对所有可能的属性只运行一次majorAgents.Any 查询。为此,您可以尝试连接firstNamelastNameaddressProof 字段并检查majorAgent 字符串是否存在于此连接字符串中的任何位置。

注意:我有意修改了Address 相关条件,因为它似乎与手头的任务无关。在原始查询中,它说:w.Address.Any(s=&gt;majorAgents.Contains(s.addressProof),这意味着“如果有任何地址证明,请检查主要代理”,而检查 addressProof of any Address has any of the majorAgents 是否更明智。为此,我使用了w.Address.SelectMany(a =&gt; a.addressProof).ToArray()string.Join,这将为我提供空格分隔的addressProof 字符串,我可以在其中查找任何majorAgent。如果这不是预期的,请根据要求修改地址的那部分。

所以,修改后的查询是:

var majorAgents = new[]  "iPhone", "Android", "iPad" ;


List<Person> lstperson =_context.person.where 
                      (w=>majorAgents.Any(x=>(w.personLastName + " " + w.personFirstName + " " +string.Join(" ",w.Address.SelectMany(a => a.addressProof).ToArray())).contains(x))
                      )
                        .select(s=> new Person
                             s.personId,
                             s.perosnLastName,
                             s.personFirstName
                    ).ToList();

希望对你有帮助。

【讨论】:

我们在服务器端不使用字符串连接,所以不使用字符串连接我们可以处理性能问题。 使用 ToArray() 获取值需要时间。实际上它不会提高性能。【参考方案2】:

做 contains 会比做一个 'any' 更有表现力。 进行以下测试:

var majorAgents = new[]  "iPhone", "Android", "iPad" ;

List<Person> lstperson=_context.person.where 
     (c=> majorAgents.contains(c.personLastName) || majorAgents.contains(c.personFirstName))
    .select(s=> new Person
             s.PersonId,
             s.perosnLastName,
             s.personFirstName
).ToList();

【讨论】:

谢谢@jonathan,删除它的速度有点快,但我需要进一步提高性能...... 如果我使用了另一个表,我在 Linq 中使用 Any() >List lstperson=_context.person.where (c=> majorAgents.contains(c.personLastName) || majorAgents.contains (c.personFirstName) && Address.Any(majorAgents.contains(c.addressProof))) .select(s=> new Person s.PersonId, s.perosnLastName, s.personFirstName ).ToList(); 原始查询和这个查询做不同的事情。问题中的一个将检查majorAgents 是否包含在personLastName 中。这将检查 personLastName 是否包含在 majorAgents 数组中。 @JohnBoker 是正确的,修改后的包含查询与原来的 Any 查询不同

以上是关于在 Linq 中使用多个包含需要时间来加载性能问题的主要内容,如果未能解决你的问题,请参考以下文章

具有多个包含的Linq-to-Sql

使用 Linq 执行具有多个值的包含

在 NHibernate 3.0 Linq 中急切加载多个兄弟姐妹和孙辈(堂兄弟?)的良好行为

如何使用方法语法在 LINQ 连接中添加多个条件

计算数组的非空元素 - LINQ 性能问题 [重复]

在 EFCore 急切加载 LINQ 查询中,如何在 ThenInclude() 表达式中引用***实体?