2011-05-09 5 views
75

Básicamente, inserto 35000 objetos dentro de una transacción:¿Por qué la inserción de entidades en EF 4.1 es tan lenta en comparación con ObjectContext?

using(var uow = new MyContext()){ 
    for(int i = 1; i < 35000; i++) { 
    var o = new MyObject()...; 
    uow.MySet.Add(o); 
    } 
    uow.SaveChanges(); 
} 

Esto toma siempre! Si utilizo el ObjectContex t subyacente (usando IObjectAdapter), sigue siendo lento pero tarda alrededor de 20 segundos. Parece que DbSet<> está realizando algunas búsquedas lineales, que toma una cantidad de tiempo cuadrada ...

¿Alguien más está viendo este problema?

+3

de alguna manera yo creo que la respuesta será similar a esto: http://stackoverflow.com/questions/5917478/what-causes-attach -to-be-slow-in-ef4/5921259 # 5921259 –

Respuesta

119

Como ya se ha indicado por Ladislav en el comentario, es necesario deshabilitar la detección de cambios automática para mejorar el rendimiento:

context.Configuration.AutoDetectChangesEnabled = false; 

Esta detección de cambios está habilitado de forma predeterminada en la API DbContext.

La razón por la DbContext se comporta de manera diferente a la API ObjectContext es que muchas más funciones de la API DbContext llamarán DetectChanges internamente que las funciones de la API ObjectContext cuando se habilita la detección de cambios automática.

Here puede encontrar una lista de esas funciones que llaman DetectChanges de forma predeterminada. Ellos son:

  • El Add, Attach, Find, Local, o Remove miembros en DbSet
  • El GetValidationErrors, Entry, o SaveChanges miembros en DbContext
  • El método Entries en DbChangeTracker

Especialmente Add llama al DetectChanges que es responsable del bajo rendimiento que experimentó.

I contraste a esto el API ObjectContext llama DetectChanges solamente automáticamente en SaveChanges pero no en AddObject y los otros métodos correspondientes se mencionó anteriormente. Esa es la razón por la cual el rendimiento predeterminado de ObjectContext es más rápido.

¿Por qué introdujeron esta detección automática de cambio predeterminada en DbContext en tantas funciones? No estoy seguro, pero parece que deshabilitarlo y llamar al DetectChanges manualmente en los puntos correctos se considera advanced and can easily introduce subtle bugs into your application so use [it] with care.

+0

@Ladislav: Tienes razón, no encontré esto, ya que solo estaba buscando problemas de inserción :-( – Hartmut

+0

Gracias por la explicación. En realidad estaba llamando contexto .Configuration.AutoDetectChangesEnabled = false pero lo hice durante la construcción de la base de datos en el método Seed(). Pensé que esto establecería el valor predeterminado. No sabía que tenía que llamarlo para cada instancia. ¡Gracias! – Hartmut

+3

@Hartmut: puede desactivar la detección de cambios dentro del constructor de su DbContext derivado, luego lo tiene siempre deshabilitado. Pero personalmente, de alguna manera, este comentario sobre "introducir posibles errores sutiles" cuando está desactivado me pone nervioso. Tengo la detección de cambios activada de manera predeterminada y la desactivo solo en bloques de código como el suyo donde el aumento de rendimiento es obvio y en el que me siento seguro de que no causa problemas. – Slauma

9

Pequeña prueba empírica con EF 4.3 CodeFirst:

eliminados 1000 objetos con AutoDetectChanges = true: 23 seg

eliminados 1000 objetos con AutoDetectChanges = false: 11 sec

insertados 1000 objetos con AutoDetectChanges = true: 21 sec

insertado 1000 objetos con AutoDetectChanges = falso: 13 segundos

+1

Gracias Zax. ¿Cuáles son sus resultados con 35,000 según la pregunta? Verás que en la pregunta original se dice que el rendimiento cae cuadráticamente –

0

Además de las respuestas que ha encontrado aquí. Es importante saber que en el nivel de la base de datos es más trabajo insertar que agregar. La base de datos debe ampliar/asignar nuevo espacio. Luego tiene que actualizar al menos el índice de clave principal. Aunque los índices también pueden actualizarse al actualizar, es mucho menos común. Si hay claves externas, tiene que leer esos índices también para asegurarse de que se mantenga la integridad referencial. Los desencadenantes también pueden desempeñar un papel, aunque pueden afectar las actualizaciones de la misma manera.

Todo el trabajo de la base de datos tiene sentido en la actividad de inserción diaria originada por las entradas de usuario. Pero si solo está cargando una base de datos existente, o tiene un proceso que genera muchas inserciones. Es posible que desee buscar formas de acelerar eso, posponiéndolo hasta el final. Normalmente, deshabilitar índices al insertar es una forma común. Hay optimizaciones muy complejas que se pueden hacer dependiendo del caso, pueden ser un poco abrumadoras.

Simplemente sepa que, en general, insertar llevará más tiempo que las actualizaciones.

2

En este .netcore 2.0 fue trasladado a:

context.ChangeTracker.AutoDetectChangesEnabled = false;

Cuestiones relacionadas