代码之家  ›  专栏  ›  技术社区  ›  andrewb

有没有办法改进这个EF查询

  •  0
  • andrewb  · 技术社区  · 7 年前

    在第三方使用的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))
    

    keys是检索到的lead ID的IEnumerable。基本上,我们提取ID列表,然后执行上述操作,检查密钥集合,以便查询返回准确的数据。

    密钥可容纳约28k个ID。

    请注意,这在迁移到Azure云后才开始成为一个问题,但我认为这是一个巧合

    2 回复  |  直到 7 年前
        1
  •  1
  •   Steve Py    7 年前

    为了帮助澄清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. /*);
    

    public class Lead
    {
       //...
       public virtual Config Config { get; set; }
    }
    

    然后,如果这是EF core,则设置映射:(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.
    

    或EF6

    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属性以获取该lead的配置。不需要编写查询来分别返回Lead和Config以及其他数据。你不需要 .Include() 但是,如果要在通过属性进行查询后访问这些实体,则应使用 以避免对数据库进行额外的延迟加载调用(EF的一个强大功能,但如果不小心使用,这是一个昂贵的功能。)

        2
  •  1
  •   Community Mohan Dere    5 年前

    keys是检索到的lead ID的IEnumerable。

    因此:

    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))
    

    SELECT … WHERE LeadId in (1,23,3,4,5,6,45,34, . . . )
    

    基本上,我们提取ID列表,然后执行上述操作

    那就别那么做。如果您想要的ID列表在数据库中,那么将其加入到您的查询中。避免从数据库中读取28K ID,然后将其发送回查询体。