Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What causes .Attach() to be slow in EF4?

We have a generic update method in our code that does a

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

I'm testing this out by passing in an enumeration of entities and calling this once per entity.

What I'm finding is that an enumeration of 1000 entities takes approximately 47s to run. Is that expected behavior? Or is there something wrong with the code snippet?

Profiling showed the Attach() method was slower than the SetState() method.

The test I ran it on was on an entity with 50 properties and no relations if that has any impact.

like image 377
taylonr Avatar asked May 06 '11 22:05

taylonr


People also ask

Why is EF slow?

Answer. Entity Framework loads very slowly the first time because the first query EF compiles the model. If you are using EF 6.2, you can use a Model Cache which loads a prebuilt edmx when using code first; instead, EF generates it on startup.

What does Dbset attach do?

Attach is used to repopulate a context with an entity that is known to already exist in the database. SaveChanges will therefore not attempt to insert an attached entity into the database because it is assumed to already be there.

What is Entity Framework performance?

At its heart, Entity Framework is a way of exposing . NET objects without actually knowing their values, but then fetching / updating those values from the database behind the scenes when you need them. It's important to be aware of when EF is going to hit the database – a process called materialization.


1 Answers

I can confirm this slow behaviour and I also found the main reason. I've made a little test with the following model ...

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

... and this test program ...

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

Test 1

Exactly the code above:

--> time = 29,2 sec


Test 2

Comment out the line ...

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

--> time = 15,3 sec


Test 3

Comment out the line ...

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

--> time = 57,3 sec

This result is very strange because I expected that calling Attach is not necessary because changing the state attaches anyway.


Test 4

Remove properties P6 to P50 (so we only have 5 strings in the entity), original code:

--> time = 3,4 sec

So, yes, obviously the number of properties strongly matters.


Test 5

Add the following line before the loop (model again with all 50 properties):

context.Configuration.AutoDetectChangesEnabled = false; 

--> time = 1,4 sec


Test 6

Again with AutoDetectChangesEnabled = false but with only 5 properties:

--> time = 1,3 sec

So, without change tracking the number of properties doesn't matter so much anymore.


Conclusion

By far most of the time seems to be spent for taking the snapshot of the attached object's properties by the change tracking mechanism. If you don't need it disable change tracking for your code snippet. (I guess in your code your really don't need change tracking because by setting the entitiy's state to Modified you basically mark all properties as changed anyway. So all columns get sent to the database in an update statement.)

Edit

The test times above are in Debug mode. But Release mode doesn't make a big difference (for instance: Test 1 = 28,7 sec, Test 5 = 0,9 sec).

like image 161
Slauma Avatar answered Sep 28 '22 03:09

Slauma