entity framework - practices - Problema de rendimiento del marco de la entidad, saveChanges es muy lento
entity framework precompiled query (5)
" AsNoTracking " funciona para mí
ex:
Item itemctx = ctx.Items.AsNoTracking().Single(i=>i.idItem == item.idItem);
ctx.Entry(itemctx).CurrentValues.SetValues(item);
itemctx.images = item.images;
ctx.SaveChanges();
Sin "AsNoTracking" las actualizaciones son muy lentas.
Recientemente, estoy haciendo un trabajo simple de EF. Muy simple, primero,
List<Book> books = entity.Books.WHERE(c=>c.processed==false)ToList();
then
foreach(var book in books)
{
//DoSomelogic, update some properties,
book.ISBN = "ISBN " + randomNumber();
book.processed = true;
entity.saveChanges(book)
}
entity.saveChanges
dentro del foreach
porque es una lista grande, alrededor de 100k registros, y si este registro se procesa sin problemas, luego marque este registro, establezca book.processed = true, si el proceso es interrumpido por excepción, luego Tiempo, no tengo que procesar estos buenos registros de nuevo.
Todo me parece bien. Es rápido cuando procesas cientos de registros. Luego, cuando nos movemos a 100k registros, entity.saveChanges es muy lento. alrededor de 1-3 segundos por registro. Luego mantenemos el modelo de la entidad, pero reemplazamos entity.saveChanges
con el SqlHelper.ExecuteNonQuery("update_book", sqlparams)
clásico SqlHelper.ExecuteNonQuery("update_book", sqlparams)
. Y es muy rápido.
¿Alguien podría decirme por qué proceso de marco de entidad tan lento? Y si todavía quiero usar entity.saveChanges, ¿cuál es la mejor manera de mejorar el rendimiento?
Gracias
Desactive el seguimiento de cambios antes de realizar sus inserciones. Esto mejorará significativamente su rendimiento (magnitudes de orden). Poner a SaveChanges()
fuera de tu bucle también te ayudará, pero desactivar el seguimiento de cambios te ayudará aún más.
using (var context = new CustomerContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
// A loop to add all your new entities
context.SaveChanges();
}
Vea esta página para más información.
El Entity Framework, en mi opinión, es una mala elección para operaciones BULK tanto desde el punto de vista del rendimiento como del consumo de memoria. Una vez que obtiene más de unos pocos miles de registros, el método SaveChanges realmente comienza a descomponerse.
Puede intentar dividir su trabajo en transacciones más pequeñas, pero nuevamente, creo que está trabajando demasiado para crear esto.
Un enfoque mucho mejor es aprovechar las operaciones a GRANEL que ya proporciona su DBMS. SQL Server proporciona COPIA A GRANEL a través de .NET. Oracle proporciona COPIA A GRANEL para el acceso a datos de Oracle.DataAccess o no administrado. Para Oracle.ManagedDataAccess, la biblioteca BULK COPY desafortunadamente no está disponible. Pero puedo crear un procedimiento almacenado de Oracle utilizando BULK COLLECT / FOR ALL que me permite insertar miles de registros en segundos con una huella de memoria mucho menor dentro de su aplicación. Dentro de la aplicación .NET, puede implementar matrices asociativas PLSQL como parámetros, etc.
La ventaja de aprovechar las facilidades BULK dentro de su DBMS es reducir los cambios de contexto entre su aplicación, el procesador de consultas y el motor de base de datos.
Estoy seguro de que otros proveedores de bases de datos proporcionan algo similar.
También puedo recomendarle que saque el SaveChanges () del bucle, ya que hace ''n'' el número de actualizaciones a la base de datos, por lo que el contexto tendrá ''n'' veces para iterar a través de los puntos de verificación y validaciones requeridas.
var books = entity.Books.Where(c => c.processed == false).ToList();
books.Foreach(b =>
{
b.ISBN = "ISBN " + randomNumber();
b.processed = true;
//DoSomelogic, update some properties
});
entity.SaveChanges();
Tomaría el SaveChanges (libro) fuera del foreach. Dado que el libro está en la entidad como una lista, puede colocarlo fuera y EF funcionará mejor con el código resultante.
La lista es un atributo en la entidad, y EF está diseñado para optimizar las actualizaciones / crea / elimina en la base de datos back-end. Si haces esto, sería curioso si ayuda.