2010-07-27 64 views
12

Actualmente estoy investigando el uso de db4o como almacenamiento para mi aplicación web. Estoy bastante contento de lo fácil que funciona db4o. Entonces, cuando leo sobre el enfoque de Code First que me gusta, es porque la forma de trabajar con EF4 Code First es bastante similar a trabajar con db4o: crear objetos de dominio (POCO), lanzarlos a db4o y nunca mirar hacia atrás.¿Por qué el código EF4 primero es tan lento cuando se almacenan objetos?

Pero cuando hice una comparación de rendimiento, EF 4 fue terriblemente lento. Y no pude entender por qué.

que utilice las siguientes entidades:

public class Recipe { private List _RecipePreparations; public int ID { get; set; } public String Name { get; set; } public String Description { get; set; } public List Tags { get; set; } public ICollection Preparations { get { return _RecipePreparations.AsReadOnly(); } }

public void AddPreparation(RecipePreparation preparation) 
    { 
     this._RecipePreparations.Add(preparation); 
    } 
} 

clase pública RecipePreparation { Nombre de la cadena pública {get; conjunto; } public String Descripción {get; conjunto; } public int Rating {get; conjunto; } public List Steps {get; conjunto; } public List Tags {get; conjunto; } public int ID {get; conjunto; }}

Para probar el rendimiento I nuevo una receta, y añadir 50.000 RecipePrepations. Entonces almacenado el objeto de db4o así:

IObjectContainer db = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(), @"RecipeDB.db4o"); 
db.Store(recipe1); 
db.Close(); 

Esto toma alrededor de 13.000 (ms)

almaceno las cosas con EF4 en SQL Server 2008 (Express, localmente) como este:

cookRecipes.Recipes.Add(recipe1); 
cookRecipes.SaveChanges(); 

y que lleva 200.000 (ms)

Ahora, ¿cómo en la tierra es db4o 15 (!!!) veces más rápido que EF4/SQL? ¿Me estoy perdiendo un botón turbo secreto para EF4? Incluso creo que db4o podría hacerse más rápido? Como no inicializo el archivo de la base de datos, simplemente lo dejo crecer de forma dinámica.

+1

Mi conjetura es que la sobrecarga de muchos insert-declaraciones individuales en ejecución es la porción más grande de la diferencia. ¿Hay alguna manera de instruir a EF4 para que combine las instrucciones de inserción para reducir esa sobrecarga? –

+0

@Lasse: Sí, lo hay. EF implementa el patrón de la unidad de trabajo de la caja: mira mi respuesta. –

+1

He hecho algunos perfiles con Visual Studio. Y el cookRecipes.Recipes.Add (receta1) toma aproximadamente el 65% del tiempo total para almacenar, y SaveChanges aproximadamente el 35% (duh ...;)). – Saab

Respuesta

3

¿Ha llamado SaveChanges()dentro de el lazo? ¡No es de extrañar que sea lento! Trate de hacer esto:

foreach(var recipe in The500000Recipes) 
{ 
    cookRecipes.Recipes.Add(recipe); 
} 
cookRecipes.SaveChanges(); 

EF espera que usted haga todos los cambios que desee y, a continuación, llamar SaveChanges vez. De esta forma, puede optimizar la comunicación de la base de datos y sql para realizar los cambios entre el estado de apertura y el estado de ahorro, ignorando todos los cambios que haya deshecho. (Por ejemplo, agregar 50 000 registros y luego eliminar la mitad de ellos, y luego presionar SaveChanges solo agregará 25 000 registros a la base de datos.)

+0

El bucle era antes de almacenar datos en db4o o EF4/SQL. Así que primero reálgo Receta, luego en un bucle agrego las RecetasPreparaciones. Así que ahora tengo una Receta, con 50,000 RecetaPreparación adjunta. Luego guardo esto en db4o o EF4/SQL. Así que un db.store único (receta1) en db4o, y un solo cookRecipes.Recipes.Add (receta1); cookRecipes.SaveChanges() en EF4. – Saab

+0

DB4O está guardando en un archivo en su máquina local ¿verdad? Y EF4 tiene que abrir una conexión de base de datos localmente. La conexión normalmente permanecerá abierta, por lo que es un costo de una vez por lanzamiento. Intente agregar una línea para obtener el primer elemento de la base de datos antes de que su ciclo de temporización inserte el tiempo de conexión fuera de la ecuación. – DamienG

1

El EF se destaca en muchas cosas, pero la carga masiva no es una de ellas . Si desea una carga masiva de alto rendimiento, hacerlo directamente a través del servidor de base de datos será más rápido que cualquier ORM. Si la única restricción de rendimiento de su aplicación es la carga masiva, entonces probablemente no debería usar el EF.

+0

Entonces tengo dudas sobre el uso de EF. Cuando su aplicación depende de un Modelo muy complejo (objetos de dominio), entonces prefiero una base de datos oo (como db4o). Pero cuando los datos son principalmente tabulares, se usaría una base de datos relacional tradicional con, y opcionalmente, un OR/M como EF. Pero como dices, EF falla cuando haces cargas/inserciones/actualizaciones pesadas. Entonces, lo que temía es realmente cierto. EF4 es solo una opción cuando se realizan operaciones de base de datos muy livianas, y uno está atrapado en el uso de una base de datos relacional. – Saab

+1

Nuevamente, no solo EF, sino * cualquier * ORM será más lento que las características de carga masiva de un servidor de BD. El EF puede ser más lento que los ORM que admiten inserciones masivas, pero incluso esos no serán tan rápidos como las API de transmisión utilizadas en las funciones de carga masiva dedicadas del servidor de BD. La carga masiva es un caso de esquina para la mayoría de las aplicaciones, pero si es su pan de cada día, sería mejor utilizar algo como SSIS que un ORM. –

+0

Acepto que la mayoría de los OR/M serán más lentos que solo la carga masiva. Pero no estoy de acuerdo con que un OR/M tampoco pueda hacer uso de las funciones de carga masiva de una base de datos. El código es muy fácil de generar. Pero creo que algo va mal con EF4 Code First. Ya que solo agregar la entidad Recipe al dbContext toma mucho tiempo (130 segundos). El almacenamiento en la base de datos (dbContext.Recipes.SaveChanges) tampoco es un demonio de velocidad, 70 segundos para 50.001 filas. Lo que se traduce en 50,000/70 = 714 filas/s. – Saab

1

Solo para agregar a las otras respuestas: db4o normalmente se ejecuta en proceso, mientras que EF abstrae una base de datos fuera de proceso (SQL). Sin embargo, db4o es esencialmente de subproceso único.Entonces, si bien podría ser más rápido para este único ejemplo con una solicitud, SQL manejará la concurrencia (múltiples consultas, múltiples usuarios) mucho mejor que una configuración predeterminada de la base de datos db4o.

Cuestiones relacionadas