c# performance entity-framework sql-server-2008

c# - ¿Cómo puedo acelerar DbSet.Add()?



performance entity-framework (5)

Cada elemento de una unidad de trabajo tiene una sobrecarga, ya que debe verificar (y actualizar) el administrador de identidades, agregar a varias colecciones, etc.

Lo primero que intentaría es agrupar, por ejemplo, grupos de 500 (cambiar ese número para adaptarlo), comenzando con un contexto de objeto nuevo (nuevo) cada vez; de lo contrario, puede esperar razonablemente un rendimiento de telescopía. Romperlo en lotes también evita que una transacción megalítica haga que todo se detenga.

Más allá de eso; SqlBulkCopy. Está diseñado para grandes importaciones con gastos generales mínimos. Aunque no es EF

Tengo que importar aproximadamente 30k filas de un archivo CSV a mi base de datos SQL, esto lamentablemente toma 20 minutos.

La resolución de problemas con un generador de perfiles me muestra que DbSet.Add está tardando más tiempo, pero ¿por qué?

Tengo estas clases de Entity Framework Code-First:

public class Article { // About 20 properties, each property doesn''t store excessive amounts of data } public class Database : DbContext { public DbSet<Article> Articles { get; set; } }

Para cada elemento en mi bucle for hago:

db.Articles.Add(article);

Fuera del bucle for hago:

db.SaveChanges();

Está conectado con mi servidor SQLExpress local, pero supongo que no hay nada escrito hasta que se llame a SaveChanges, así que supongo que el servidor no será el problema ...


Hay una extensión extremadamente fácil de usar y muy rápida aquí: https://efbulkinsert.codeplex.com/

Se llama "Entity Framework Bulk Insert".

La extensión en sí está en el espacio de nombres EntityFramework.BulkInsert.Extensions. Así que para revelar el método de extensión agregar usando

using EntityFramework.BulkInsert.Extensions;

Y luego puedes hacer esto

context.BulkInsert(entities);

Por cierto, si no desea utilizar esta extensión por algún motivo, también puede probar en lugar de ejecutar db.Articles.Add (artículo) para cada artículo, para crear cada vez una lista de varios artículos y luego usar AddRange (nuevo en EF versión 6, junto con RemoveRange) para agregarlos juntos al dbcontext.


Realmente no he intentado esto, pero mi lógica sería aferrarse al controlador ODBC para cargar el archivo en la tabla de datos y luego usar el procedimiento almacenado SQL para pasar la tabla al procedimiento.

Para la primera parte, intente: http://www.c-sharpcorner.com/UploadFile/mahesh/AccessTextDb12052005071306AM/AccessTextDb.aspx

Para la segunda parte, intente esto para el procedimiento SQL: http://www.builderau.com.au/program/sqlserver/soa/Passing-table-valued-parameters-in-SQL-Server-2008/0,339028455,339282577,00.htm

Y cree el objeto SqlCommnand en c # y agréguelo a su colección de parámetros SqlParameter que es SqlDbType.Structured

Bueno, espero que ayude.


Según el comentario de Kevin Ramen (29 de marzo), puedo confirmar que la configuración de db.Configuration.AutoDetectChangesEnabled = false hace una gran diferencia en la velocidad

Al ejecutar Add() en 2324 elementos, se ejecutaron 3min 15sec en mi máquina de forma predeterminada, al deshabilitar la detección automática, la operación se completó en 0.5sec.

http://blog.larud.net/archive/2011/07/12/bulk-load-items-to-a-ef-4-1-code-first-aspx


Voy a agregar al comentario de Kervin Ramen diciendo que si solo está haciendo inserciones (sin actualizaciones o eliminaciones), en general, puede configurar de forma segura las siguientes propiedades antes de hacer inserciones en el contexto:

DbContext.Configuration.AutoDetectChangesEnabled = false; DbContext.Configuration.ValidateOnSaveEnabled = false;

Estaba teniendo un problema con una importación masiva única en mi trabajo. Sin establecer las propiedades anteriores, agregar alrededor de 7500 objetos complicados al contexto tomó más de 30 minutos. La configuración de las propiedades anteriores (por lo que la desactivación de las comprobaciones EF y el seguimiento de cambios) redujo la importación a segundos.

Pero, nuevamente, enfatizo que solo use esto si está haciendo inserciones. Si necesita mezclar inserciones con actualizaciones / eliminaciones, puede dividir su código en dos rutas y deshabilitar las comprobaciones EF para la parte insertada y luego volver a habilitar las comprobaciones para la actualización / eliminar ruta. He utilizado este enfoque con éxito para sortear el DbSet.Add() lento de DbSet.Add() .