1

我希望我能得到一些帮助来解决我在 EntityFramework 4.4 中遇到的性能问题。我正在将一个使用 EDMX 文件的应用程序首先转换为代码,并且在 LINQ 查询的“where”子句中运行具有大量对象的查询时遇到了问题。

以下是对所有内容的布局方式的简要概述(实体不是指 EF,它是我们代码中为通用“事物”提供的名称):

public class ExampleDbContext : DbContext
{
    public DbSet<EntityTag> EntityTags { get; set; }
    public DbSet<Entity> Entities { get; set; }

    public DbSet<Log> Logs { get; set; }

    protected override void OnModelCreating(DbmodelBuilder modelBuilder)
    {
        // Fluent mappings added to modelBuilder.Configurations.Add() in here
    }
}

public class EntityTag
{
    public int Id { get; set; }

    public virtual Entity Entity { get; set; }
    public int EntityId { get; set; }

    public virtual Log Deleted { get; set; }
    public int? DeletedId { get; set; }
}

public class Entity
{
    public int Id { get; set; }

    pulic byte[] CompositeId { get; set; }
}

// Used to log when an event happens
public class Log
{
    public int Id { get; set; }

    public string Username { get; set; }
    public DateTime Timestamp { get; set; }
}

我正在运行的导致问题的查询是:

// Creates an IEnumerable<byte[]> with the keys to find
var computedKeys = CreateCompositeIDs(entityKeys);

// Run the query and find any EntityTag that isn't deleted and is in
// the computedKeys list
var result = from et in Context.EntityTags
             where computedKeys.Contains(et.Entity.CompositeId) &&
                   et.Deleted == null
             select et;

var entityTags = result.ToList();

当 computedKeys 仅包含几个 Id(例如 15 个)时,代码和查询会快速运行。当我有大量 Id(此时 1600 是正常的,并且可能会变得更高)时,一旦使用ToList(). 我还computedKeys.Contains()从查询中删除了大量的(离开 et.Deleted),computedKeys并且查询最终快速运行。

通过调试,我确定创建键列表很快,所以这不是问题。当我将探查器连接到 MSSQL 以查看生成的查询时,它看起来很正常,因为所有 CompositeId 都包含在 a 中WHERE CompositeId IN ( /* List of Ids, could be 1500 of them */),并且当查询显示在探查器中时,它会在不到一秒的时间内执行,所以我不认为它是数据库优化的事情,要么。分析器将坐在那里,在它运行的整个过程中,从最后一秒左右开始,当它快速返回结果时,它不会出现任何东西。

我连接了 dotTrace,看起来很多时间都花在System.Data.Query.PlanCompiler.JoinGraph.GenerateTransitiveEdge(JoinEdge, JoinEdge)(119,640 毫秒)System.Collections.Generic.List+Enumerator内,我认为,根据每个方法的总执行时间,在该方法中调用了 1.MoveNext`(54,270 毫秒)两次。

我似乎无法弄清楚为什么生成查询需要这么长时间。编译后第二次执行似乎也没有更快,所以它看起来不像被缓存。

在此先感谢您的帮助!

4

1 回答 1

0

我能够弄清楚。一旦我决定不保留原始查询并重新考虑结果,我将查询重写为:

var computedKeys = CreateCompositeIDs(entityKeys);

var entityTags = (from e in Context.Entities
                  where computedKeys.Contains(e.CompositeId)
                  from et in e.Tags
                  select et).Distinct();
entityTags = from et in entityTags
             where et.Deleted == null
             select et;

return entityTags;

当我开始直接查询实体并利用与EntityTag(我忘记包含在原始问题中......)的关系时Tags,然后只过滤现有的EntityTag,它加快了查询速度,使其全部运行在一个之下第二。

于 2013-02-11T16:35:05.653 回答