今天,在第三方使用的WebApi中,当我们调用方法时,我们开始遇到失败。
该方法连接到几个表并将它们联接起来。 EF的错误消息是
查询处理器用尽了内部资源,无法生成查询计划。这是罕见的事件,仅在极其复杂的查询或引用大量表或分区的查询中才会发生。请简化查询。如果您认为收到此消息是错误的,请联系客户支持服务以获取更多信息。
return context.leads
.Where(q => q.eventID == 1234)
.Join(context.config,
leads => leads.configId,
config => config.configId,
(leads, config) => new { leads, config })
.Where(p => keys.Contains(p.leads.leadId))
键是检索到的潜在顾客ID的IEnumerable。基本上,我们提取ID列表,然后执行上述操作,检查键集合,以便我们的查询返回准确的数据。
密钥包含约28k个ID。
请注意,自迁移到Azure云以来,这才刚刚成为一个问题,但这是一个巧合
答案 0 :(得分:1)
键是检索到的潜在顾客ID的IEnumerable。
密钥包含约28k个ID。
所以这个:
return context.leads
.Where(q => q.eventID == 1234)
.Join(context.config,
leads => leads.configId,
config => config.configId,
(leads, config) => new { leads, config })
.Where(p => keys.Contains(p.leads.leadId))
会将ID粘贴到SQL查询文本中,例如:
SELECT … WHERE LeadId in (1,23,3,4,5,6,45,34, . . . )
导致大型,不可重用且昂贵的解析和编译查询。最好将ID加载到表中并加入它们,或者使用XML,JSON或表值参数将其传递到服务器。
基本上,我们提取ID列表,然后执行上面的操作
那就不要那样做。如果所需的ID列表在数据库中,则将其加入查询中。避免从数据库中读取28K ID,然后将其发送回查询正文中。
答案 1 :(得分:1)
为帮助澄清David的回答:
您用来获取28k ID的查询是什么?那是您应该合并到该查询中的查询。提取ID对于#相对较小的ID(而不是28k)可以正常工作。如果在EF中正确设置了关系,则可以避免显式联接。 EF不仅是SQL的替代包装。尽管您可以使用断开连接的实体之间的显式联接来编写它,但是当设置为ORM时,相关实体之间会相互了解,它的功能要强大得多。您的EF表达式应该更像:
var leadsQuery = context.leads
.Include(l => l.Config)
.Where(l => l.eventID == 1234
&& /* Insert criteria to determine which Leads to return. /*);
要插入的where子句是IEnumerable ID中的 not 。这对于少量的行很好用。相反,这应该是您用来获取这些ID的标准。
线索应具有对Config的引用。无需为每个表声明DbSet,然后告诉EF将它们加入。如果Lead表具有ConfigId,则:
public class Lead
{
//...
public virtual Config Config { get; set; }
}
然后,如果这是EF核心,则设置映射:(IEntityTypeConfiguration或OnModelCreating)
builder.Entity<Lead>()
.HasOne(x => x.Config)
.WithMany() // Lead has a config, Config does not have a collection of Leads.
.HasForeignKey("ConfigId"); // Creates a shadow property for the FK.
或EF 6
builder.Entity<Lead>()
.HasRequired(x => x.Config)
.WithMany()
.Map(x => x.MapKey("ConfigId")); // Similar to above. Set up the relationship without a FK in the entity, map directly to the table.
通过使用.Include(l => l.Config)
,您可以访问lead.Config属性以获取该线索的Config。无需编写查询来分别返回线索和配置以及其他数据。您无需.Include()
来查询相关实体,但是,如果要在查询后通过属性访问那些实体,则应使用.Include()
以避免额外的延迟加载回调到数据库。 (EF的一项强大功能,但如果使用不当,则价格昂贵。)