Básicamente, inserto 35000 objetos dentro de una transacción:
using(var uow = new MyContext()){
for(int i = 1; i < 35000; i++) {
var o = new MyObject()...;
uow.MySet.Add(o);
}
uow.SaveChanges();
}
¡Esto lleva una eternidad! Si utilizo la ObjectContex
t subyacente (mediante el uso IObjectAdapter
), todavía es lento pero tarda alrededor de 20 segundos. Parece que DbSet<>
está haciendo algunas búsquedas lineales, lo que lleva bastante tiempo ...
¿Alguien más está viendo este problema?
c#
entity-framework
entity-framework-4.1
Hartmut
fuente
fuente
Respuestas:
Como ya lo indicó Ladislav en el comentario, debe deshabilitar la detección automática de cambios para mejorar el rendimiento:
context.Configuration.AutoDetectChangesEnabled = false;
Esta detección de cambios está habilitada de forma predeterminada en la
DbContext
API.La razón por la que se
DbContext
comporta de manera tan diferente de laObjectContext
API es que muchas más funciones de laDbContext
API llamaránDetectChanges
internamente que funciones de laObjectContext
API cuando la detección automática de cambios está habilitada.Aquí puede encontrar una lista de las funciones que llaman
DetectChanges
por defecto. Son:Add
,Attach
,Find
,Local
, oRemove
miembros deDbSet
GetValidationErrors
,Entry
, oSaveChanges
miembros deDbContext
Entries
método enDbChangeTracker
Especialmente las
Add
llamadasDetectChanges
que son responsables del bajo rendimiento que experimentó.En contraste con esto, la
ObjectContext
API llamaDetectChanges
solo automáticamente enSaveChanges
pero no enAddObject
y los otros métodos correspondientes mencionados anteriormente. Esa es la razón por la que el rendimiento predeterminado deObjectContext
es más rápido.¿Por qué introdujeron esta detección automática de cambios predeterminada
DbContext
en tantas funciones? No estoy seguro, pero parece que deshabilitarlo y llamarDetectChanges
manualmente en los puntos adecuados se considera avanzado y puede introducir fácilmente errores sutiles en su aplicación, así que utilícelo con cuidado .fuente
Pequeña prueba empírica con EF 4.3 CodeFirst:
Se eliminaron 1000 objetos con AutoDetectChanges = true: 23 segundos
Se eliminaron 1000 objetos con AutoDetectChanges = false: 11 segundos
Se insertaron 1000 objetos con AutoDetectChanges = true: 21 segundos
Se insertaron 1000 objetos con AutoDetectChanges = false: 13 segundos
fuente
En .netcore 2.0 esto se movió a:
context.ChangeTracker.AutoDetectChangesEnabled = false;
fuente
Además de las respuestas que has encontrado aquí. Es importante saber que a nivel de la base de datos es más trabajo insertar que agregar. La base de datos tiene que ampliar / asignar nuevo espacio. Luego, debe actualizar al menos el índice de clave principal. Aunque los índices también se pueden actualizar al actualizar, es mucho menos común. Si hay claves foráneas, debe 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 ese trabajo de base de datos tiene sentido en la actividad diaria de inserción originada por las entradas de los usuarios. 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 acelerarlo, posponiéndolo hasta el final. Normalmente, deshabilitar índices durante la inserción es una forma común. Hay optimizaciones muy complejas que se pueden hacer según el caso, pueden resultar un poco abrumadoras.
Solo sepa que, en general, la inserción llevará más tiempo que las actualizaciones.
fuente