是什么导致.Attach()在EF4中变慢?

tay*_*onr 26 c# entity-framework-4

我们的代码中有一个通用的更新方法

foreach (var entity in entityList)
{
    Context.GetIDbSet<T>().Attach(entity);
    Context.SetState(entity, EntityState.Modified);
}
Run Code Online (Sandbox Code Playgroud)

我通过传入一个实体的枚举并按每个实体调用一次来测试它.

我发现的是1000个实体的枚举大约需要47秒才能运行.这是预期的行为吗?或者代码片段有问题吗?

分析显示Attach()方法比SetState()方法慢.

我运行它的测试是在一个有50个属性的实体上,如果有任何影响则没有关系.

Sla*_*uma 68

我可以证实这种缓慢的行为,我也找到了主要原因.我用以下型号做了一点测试......

public class MyClass
{
    public int Id { get; set; }
    public string P1 { get; set; }
    // ... properties P2 to P49, all of type string
    public string P50 { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<MyClass> MyClassSet { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

......而且这个测试程序......

using (var context = new MyContext())
{
    var list = new List<MyClass>();
    for (int i = 0; i < 1000; i++)
    {
        var m = new MyClass()
        {
            Id = i+1,
            P1 = "Some text ....................................",
            // ... initialize P2 to P49, all with the same text
            P50 = "Some text ...................................."
        }
        list.Add(m);
    }

    Stopwatch watch = new Stopwatch();
    watch.Start();
    foreach (var entity in list)
    {
        context.Set<MyClass>().Attach(entity);
        context.Entry(entity).State = System.Data.EntityState.Modified;
    }
    watch.Stop();
    long time = watch.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)

测试1

完全是上面的代码:

- > 时间= 29,2秒


测试2

评论出来的......

//context.Entry(entity).State = System.Data.EntityState.Modified;
Run Code Online (Sandbox Code Playgroud)

- > 时间= 15,3秒


测试3

评论出来的......

//context.Set<MyClass>().Attach(entity);
Run Code Online (Sandbox Code Playgroud)

- > 时间= 57,3秒

这个结果非常奇怪,因为我预计调用Attach是不必要的,因为无论如何都要改变状态.


测试4

删除属性P6到P50(因此我们在实体中只有5个字符串),原始代码:

- > 时间= 3,4秒

所以,是的,很明显,物业的数量非常重要.


测试5

在循环之前添加以下行(再次使用所有50个属性建立模型):

context.Configuration.AutoDetectChangesEnabled = false;
Run Code Online (Sandbox Code Playgroud)

- > 时间= 1,4秒


测试6

再次使用AutoDetectChangesEnabled = false但只有5个属性:

- > 时间= 1,3秒

所以,没有变化跟踪,属性的数量就不再那么重要了.


结论

到目前为止,大部分时间似乎都花费在通过更改跟踪机制获取附加对象属性的快照.如果您不需要,请停用代码段的更改跟踪.(我想在你的代码中你真的不需要更改跟踪,因为通过设置权限的状态Modified基本上将所有属性标记为已更改.所以所有列都在更新语句中发送到数据库.)

编辑

上述测试时间处于调试模式.但释放模式没有太大的区别(例如:测试1 = 28,7秒,测试5 = 0,9秒).

  • +1这是一个很棒的解释,它是有道理的,因为快照更改跟踪被认为非常慢,但我认为慢速操作实际上是在评估更改,但这看起来像创建快照也很慢.EF的另一个问题. (2认同)