Seguí el mantra "No optimizar prematuramente" y codifiqué mi servicio WCF usando Entity Framework.
Sin embargo, hice un perfil del rendimiento y Entity Framework es demasiado lento. (Mi aplicación procesa 2 mensajes en aproximadamente 1.2 segundos, mientras que la aplicación (heredada) que estoy reescribiendo hace 5-6 mensajes al mismo tiempo (la aplicación heredada llama a sprocs para su DB Access).
Mi perfil apunta a que Entity Framework toma la mayor parte del tiempo por mensaje.
¿Entonces cuales son mis opciones?
¿Hay mejores ORM por ahí?
(Algo que solo admita la lectura y escritura normal de objetos y lo haga rápido ..)¿Hay alguna forma de hacer que Entity Framework sea más rápido?
( Nota : cuando digo más rápido me refiero a largo plazo, no a la primera llamada. (La primera llamada es lenta (15 segundos para un mensaje), pero eso no es un problema. Solo necesito que sea rápido para el resto de los mensajes.)Una tercera opción misteriosa que me ayudará a obtener más velocidad de mi servicio.
NOTA: La mayoría de mis interacciones de base de datos son Crear y Actualizar. Hago muy poco seleccionando y eliminando.
fuente
Respuestas:
Debe comenzar por perfilar los comandos SQL realmente emitidos por Entity Framework. Dependiendo de su configuración (POCO, entidades de seguimiento automático) hay mucho espacio para optimizaciones. Puede depurar los comandos SQL (que no deberían diferir entre el modo de depuración y el de liberación) utilizando el
ObjectSet<T>.ToTraceString()
método. Si encuentra una consulta que requiere una mayor optimización, puede usar algunas proyecciones para brindarle a EF más información sobre lo que está tratando de lograr.Ejemplo:
Podría ser reemplazado por:
Acabo de escribir eso de mi cabeza, por lo que no es exactamente cómo se ejecutaría, pero EF en realidad hace algunas optimizaciones agradables si le dice todo lo que sabe sobre la consulta (en este caso, que necesitaremos la categoría- nombres). Pero esto no es como una carga ansiosa (db.Products.Include ("Categorías")) porque las proyecciones pueden reducir aún más la cantidad de datos a cargar.
fuente
El hecho es que productos como Entity Framework SIEMPRE serán lentos e ineficientes, porque están ejecutando mucho más código.
También me parece una tontería que la gente sugiera que uno debe optimizar las consultas LINQ, mirar el SQL generado, usar depuradores, precompilar, tomar muchos pasos adicionales, etc., es decir, perder mucho tiempo. Nadie dice: ¡Simplifique! Todos quieren complicar las cosas aún más dando aún más pasos (perdiendo el tiempo).
Un enfoque de sentido común sería no usar EF o LINQ en absoluto. Utilice SQL simple. No tiene nada de malo. El hecho de que haya una mentalidad de manada entre los programadores y sientan la necesidad de utilizar todos los productos nuevos que existen no significa que sea bueno o que funcione. La mayoría de los programadores piensan que si incorporan cada nuevo código publicado por una gran empresa, los convierte en programadores más inteligentes; no es cierto del todo. La programación inteligente se trata principalmente de cómo hacer más con menos dolores de cabeza, incertidumbres y en el menor tiempo posible. ¡Tiempo de recordar! Ese es el elemento más importante, así que trate de encontrar formas de no desperdiciarlo resolviendo problemas en un código incorrecto / inflado escrito simplemente para ajustarse a algunos extraños llamados 'patrones'
Relájese, disfrute de la vida, tómese un descanso de la codificación y deje de usar funciones, códigos, productos y 'patrones' adicionales. La vida es corta y la vida de su código es aún más corta, y ciertamente no es ciencia espacial. Elimine capas como LINQ, EF y otras, y su código se ejecutará de manera eficiente, se escalará y, sí, seguirá siendo fácil de mantener. Demasiada abstracción es un mal "patrón".
Y esa es la solución a tu problema.
fuente
Una sugerencia es usar LINQ to Entity Framework solo para declaraciones CRUD de registro único.
Para consultas, búsquedas, informes, etc. más complejos, escriba un procedimiento almacenado y agréguelo al modelo de Entity Framework como se describe en MSDN .
Este es el enfoque que he adoptado con un par de mis sitios y parece ser un buen compromiso entre productividad y rendimiento. Entity Framework no siempre generará el SQL más eficiente para la tarea en cuestión. Y en lugar de perder el tiempo para averiguar por qué, escribir un procedimiento almacenado para las consultas más complejas en realidad me ahorra tiempo. Una vez que esté familiarizado con el proceso, no es demasiado complicado agregar procesos almacenados a su modelo EF. Y, por supuesto, el beneficio de agregarlo a su modelo es que obtiene toda esa bondad fuertemente tipada que proviene del uso de un ORM.
fuente
Si está puramente traer los datos, que es una gran ayuda para el rendimiento cuando se dice EF para no realizar un seguimiento de las entidades que descarge. Haga esto usando MergeOption.NoTracking. EF solo generará la consulta, la ejecutará y deserializará los resultados a los objetos, pero no intentará realizar un seguimiento de los cambios de entidad ni nada de esa naturaleza. Si una consulta es simple (no pasa mucho tiempo esperando que la base de datos regrese), descubrí que configurarla en NoTracking puede duplicar el rendimiento de la consulta.
Consulte este artículo de MSDN sobre la enumeración MergeOption:
Resolución de identidad, gestión de estado y seguimiento de cambios
Este parece ser un buen artículo sobre el rendimiento de EF:
Desempeño y Entity Framework
fuente
Dice que ha perfilado la aplicación. ¿También ha perfilado el ORM? Hay un generador de perfiles EF de Ayende que resaltará dónde puede optimizar su código EF. Lo puedes encontrar aquí:
http://efprof.com/
Recuerde que puede usar un enfoque SQL tradicional junto con su ORM si lo necesita para obtener rendimiento.
¿Si hay un ORM más rápido / mejor? Dependiendo de su modelo de objeto / datos, podría considerar el uso de uno de los micro-ORM, como Dapper , Massive o PetaPoco .
El sitio de Dapper publica algunos puntos de referencia comparativos que le darán una idea de cómo se comparan con otros ORM. Pero vale la pena señalar que los micro-ORM no son compatibles con el rico conjunto de funciones de los ORM completos como EF y NH.
Es posible que desee echar un vistazo a RavenDB . Esta es una base de datos no relacional (de Ayende nuevamente) que le permite almacenar POCO directamente sin necesidad de mapeo . RavenDB está optimizado para lecturas y hace la vida de los desarrolladores mucho más fácil al eliminar la necesidad de manipular el esquema y mapear sus objetos a ese esquema. Sin embargo, tenga en cuenta que este es un enfoque significativamente diferente al uso de un enfoque ORM y estos se describen en el sitio del producto .
fuente
He encontrado la respuesta de @Slauma aquí muy útil para acelerar las cosas. Usé el mismo tipo de patrón para inserciones y actualizaciones, y el rendimiento se disparó.
fuente
Desde mi experiencia, el problema no es con EF, sino con el enfoque ORM en sí.
En general, todos los ORM sufren de problemas N + 1 , no consultas optimizadas, etc. Mi mejor suposición sería rastrear las consultas que causan degradación del rendimiento e intentar ajustar la herramienta ORM, o reescribir esas partes con SPROC.
fuente
Esta es una opción simple sin marco ni ORM que se carga a 10,000 / segundo con 30 campos aproximadamente. Se ejecuta en una computadora portátil vieja, probablemente más rápido que eso en un entorno real.
https://sourceforge.net/projects/dopersistence/?source=directory
fuente
También me encontré con este problema. Odio volcar en EF porque funciona muy bien, pero es lento. En la mayoría de los casos, solo quiero encontrar un registro o actualizar / insertar. Incluso operaciones simples como esta son lentas. Retiré 1100 registros de una tabla a una lista y esa operación tomó 6 segundos con EF. Para mí esto es demasiado tiempo, incluso ahorrar lleva demasiado tiempo.
Terminé haciendo mi propio ORM. Saqué los mismos 1100 registros de una base de datos y mi ORM tomó 2 segundos, mucho más rápido que EF. Todo con mi ORM es casi instantáneo. La única limitación en este momento es que solo funciona con MS SQL Server, pero podría cambiarse para trabajar con otros como Oracle. Utilizo MS SQL Server para todo ahora mismo.
Si desea probar mi ORM, aquí está el enlace y el sitio web:
https://github.com/jdemeuse1204/OR-M-Data-Entities
O si quieres usar nugget:
PM> Paquete de instalación OR-M_DataEntities
La documentación también está ahí
fuente
Solo tiene sentido optimizar después de haber perfilado. Si descubre que el acceso a la base de datos es lento, puede realizar la conversión para usar procedimientos almacenados y mantener EF. Si descubre que el EF en sí es lento, es posible que deba cambiar a un ORM diferente o no usar un ORM en absoluto.
fuente
Tenemos una aplicación similar (Wcf -> EF -> base de datos) que realiza 120 solicitudes por segundo fácilmente, por lo que estoy más que seguro de que EF no es su problema aquí, dicho esto, he visto importantes mejoras de rendimiento con consultas compiladas.
fuente
Usé EF, LINQ to SQL y apuesto. Dapper es el más rápido. Ejemplo: necesitaba 1000 registros principales con 4 registros secundarios cada uno. Usé LINQ to sql, me tomó unos 6 segundos. Luego cambié a Dapper, recuperé 2 conjuntos de registros del único procedimiento almacenado y para cada registro agregué los registros secundarios. Tiempo total 1 segundo.
Además, el procedimiento almacenado usó funciones de valor de tabla con aplicación cruzada, encontré que las funciones de valor escalar son muy lentas.
Mi consejo sería usar EF o LINQ to SQL y, para ciertas situaciones, cambiar a apuesto.
fuente
Entity Framework no debería causar grandes cuellos de botella en sí mismo. Lo más probable es que existan otras causas. Puede intentar cambiar EF a Linq2SQL, ambos tienen funciones de comparación y el código debería ser fácil de convertir, pero en muchos casos Linq2SQL es más rápido que EF.
fuente