【问题标题】:What causes .Attach() to be slow in EF4?是什么导致 .Attach() 在 EF4 中变慢?
【发布时间】:2011-08-20 12:32:26
【问题描述】:

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

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

我正在通过传入实体枚举并为每个实体调用一次来对此进行测试。

我发现,1000 个实体的枚举运行大约需要 47 秒。 这是预期的行为吗?还是代码sn-p有问题?

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

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

【问题讨论】:

    标签: c# entity-framework-4


    【解决方案1】:

    我可以确认这种缓慢的行为,我也找到了主要原因。我用下面的模型做了一个小测试......

    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; }
    }
    

    ...还有这个测试程序...

    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;
    }
    

    测试 1

    就是上面的代码:

    --> 时间 = 29,2 秒


    测试 2

    注释掉这行...

    //context.Entry(entity).State = System.Data.EntityState.Modified;
    

    --> 时间 = 15,3 秒


    测试 3

    注释掉这行...

    //context.Set<MyClass>().Attach(entity);
    

    --> 时间 = 57.3 秒

    这个结果很奇怪,因为我认为调用Attach 是不必要的,因为无论如何都会改变状态。


    测试 4

    去掉P6到P50的属性(所以我们实体中只有5个字符串),原代码:

    --> 时间 = 3.4 秒

    所以,是的,显然属性的数量非常重要。


    测试 5

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

    context.Configuration.AutoDetectChangesEnabled = false;
    

    --> 时间 = 1.4 秒


    测试 6

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

    --> 时间 = 1,3 秒

    因此,如果不进行更改,跟踪属性的数量就不再那么重要了。


    结论

    到目前为止,更改跟踪机制似乎花费了大部分时间来获取附加对象属性的快照。 如果您不需要它,请禁用代码 sn- 的更改跟踪页。 (我猜在您的代码中您确实不需要更改跟踪,因为通过将实体的状态设置为 Modified 您基本上将 all 属性标记为已更改。所以 all 列在更新语句中发送到数据库。)

    编辑

    以上测试时间处于调试模式。但发布模式并没有太大的区别(例如:测试 1 = 28.7 秒,测试 5 = 0.9 秒)。

    【讨论】:

    • +1 这是一个很棒的解释,而且很有意义,因为快照更改跟踪被认为非常慢,但我认为缓慢的操作实际上是在评估更改,但这看起来创建快照也很慢。 EF 中的另一个问题。
    • 这是一个很棒的答案...我曾想过更改跟踪,但不知道如何将其关闭...我将在今天晚些时候尝试...谢谢
    • 做到了。太感谢了。这个错误在昨天下午 4 点左右引起了我的注意,这有点毁了我的夜晚。就像我说的那样,我正在考虑一些与跟踪有关的事情,但没有考虑上下文设置,并且可能没有到达那里。
    • 在此线程 (social.msdn.microsoft.com/Forums/en/adonetefx/thread/…) 中,有人对向 DbContext 中批量添加实体进行了类似的测量 - 结果类似:AutoDetectChangesEnabled 对性能有巨大影响.
    • @Slauma 你太棒了。这个真的咬了我们;我们认为这与更改跟踪有关,但您的精彩回答确实促成了交易!
    猜你喜欢
    • 2023-03-11
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2012-11-07
    相关资源
    最近更新 更多