¿Debería abandonar un marco ORM cuando necesita implementar una operación masiva?

15

Aquí hay una situación común:

  • Debe implementar una operación masiva en una aplicación que utiliza un marco ORM.
  • Después de la primera pasada, ha notado importantes problemas de rendimiento.

Aquí está mi pregunta:

  • En esta situación, ¿debería favorecer una solución que incluya SQL sin formato?
  • ¿O hay patrones de diseño bien conocidos que pueden ayudarlo a mitigar los problemas comúnmente asociados con las operaciones masivas con marcos ORM?

EDITAR:

  • No le pregunto si debe eliminar el marco ORM de toda la aplicación.
  • Estoy preguntando: ¿Deberías renunciar al marco ORM para esta pequeña porción de la aplicación?
Jim G.
fuente
No sé si debería hacer algo, pero ¿ha intentado agrupar su operación masiva?
ChrisAnnODell

Respuestas:

13

Los ORM no están destinados a asumir el acceso completo a su base de datos. Úselos para ese 80% de código que es CRUDO, las cosas que son demasiado tediosas para escribir por su cuenta. Utilice procedimientos almacenados, SQL dinámico o lo que desee para el 20% restante que necesita ser cuidadosamente optimizado.

Robert Harvey
fuente
44
Eso funcionaría si la abstracción de la base de datos no fuera una de las principales razones por las que decidió utilizar un ORM.
@ Pierre303, me está costando entender tu comentario. ¿Qué quieres decir?
Mark Canlas
@ MarkCanlas: Creo que quiere decir "abstraer la base de datos", en el sentido de que podría cambiar la base de datos (por ejemplo, pasar de SQL Server a MySQL) si así lo desea. En la práctica, este caso de uso casi nunca ocurre.
Robert Harvey
1
Todavía puedes crear abstracciones. La mayoría de los ORM que realmente admiten múltiples proveedores / dialectos tienen soporte para el código específico del proveedor / dialecto. Puede implementar operaciones como inserción masiva / enlace de matriz / TVP / lo que sea para bases de datos específicas y dejar que retroceda lentamente para proveedores no compatibles como SQLite. En el peor de los casos, puede dividir la funcionalidad podría ser masiva en una interfaz / clase separada y sub en una implementación diferente basada en parámetros de compilación o configuración.
Aaronaught
Sí, los dialectos personalizados pueden ayudar, así como un código específico para problemas específicos. Sin embargo, para que esto sea viable desde el punto de vista financiero, debe limitarse al mínimo estricto. Nuestras personalizaciones a través de funciones personalizadas (dialectos) representan menos del 0.1% de la base total de códigos de acceso a datos. Me preocuparía mucho si fuera más que eso.
7

Utilizo un ORM (nHibernate) en una aplicación que requiere un alto rendimiento y maneja miles de millones de registros. Con el tiempo nos dimos cuenta de que los problemas de rendimiento más importantes estaban relacionados con nuestra propia forma de usar el ORM en lugar de solo el ORM.

El ORM no debe reemplazar su conocimiento obligatorio de la base de datos. Es una herramienta que utiliza para obtener más productividad y flexibilidad en su código, pero necesitará conocer los procesos subyacentes para optimizar su rendimiento.

No especificó un ORM específico, así que aquí están las cosas que hicimos para mejorar el rendimiento:

  • Utilizamos un perfilador de ORM. (utilizamos nhprof)
  • Utilizamos un perfil de base de datos. (Utilizamos SQL Server Profiler)
  • Leemos tantos artículos como podamos sobre el tema. (Muchos estaban disponibles para nHibernate además del capítulo completo sobre el tema en la documentación)
  • Compramos libros específicos sobre rendimiento y escalabilidad.
  • Creamos un sistema de evaluación comparativa para probar nuestras propias optimizaciones.
  • y lo que es más importante, pudimos probar nuestro código con clientes de la vida real con gran cantidad de datos. Eso último solo nos ayudó a detectar la mayoría de los problemas en nuestra aplicación.
Dan McGrath
fuente
1

Logramos hacerlo con Entity Framework, pero nuestra aplicación realizó muchas operaciones de estilo por lotes (escribiríamos grandes cantidades de registros en tablas individuales), por lo que fue una buena opción. Definitivamente, vería si sería posible retener el marco ORM si es posible, solo para reducir la cantidad de código de propósito especial en su aplicación. ¿Es posible almacenar escrituras en el búfer y luego ejecutarlas como un grupo? Pierde la semántica de las transacciones, pero si va con operaciones masivas, supongo que ya ha llegado a un acuerdo con eso.

TMN
fuente
1

Los ORM no hacen nada mágico. Traducen métodos de acceso a objetos a SQL. Las instrucciones SQL que ejecutan no son necesariamente más lentas que las SQL que escribiría manualmente. Dicho esto, hay algunos problemas con los que puede tropezar:

  1. Transacciones: una operación masiva grande es casi siempre más rápida que muchas transacciones pequeñas que juntas logran lo mismo. Por lo tanto, si sus llamadas al método ORM usan transacciones detalladas (los métodos de estilo de registro activo en las entidades de Spring Roo, por ejemplo, están anotados como @Transactional por defecto), las operaciones masivas serán lentas. Si ese es el caso en su aplicación, debe mirar su lógica de transacción.
  2. Almacenamiento en caché: en Hibernate, un caché de primer nivel le permite al administrador de su entidad evitar viajes innecesarios de ida y vuelta a la base de datos. Lo bueno en general, pero malo para las inserciones masivas, donde conduce a una innecesaria obstrucción de la memoria caché, lo que da como resultado un rendimiento degradante de la aplicación. Si ese es su problema, debe mirar el patrón de procesamiento por lotes sugerido anteriormente por ChrisAnnODell. Lo usamos en nuestros importadores y acelera mucho los insertos a granel.

No hay nada de malo en usar SQL nativo para mejorar el rendimiento. Pero primero asegúrate de entender lo que te está frenando.

Wallenborn
fuente
Para evitar el caché, use una sesión sin estado. Además, evite las ID de incremento automático. HiLo o Guid deberían usarse en su lugar.
1

Omitir el ORM. No solo eso, sino que también evita el sql "regular". Use una utilidad masiva de su base de datos para insertar conjuntos de datos extremadamente grandes en una tabla de ensayo. Luego use sql para realizar sus actividades de preparación.

Su ORM "sabor del blog" puede no funcionar para todas las situaciones.

Lord Tydus
fuente
Bien, este tipo de herramientas de back-end son una molestia para aprender, pero después de aproximadamente 3 o 4 veces, serás un experto y podrás hacer las cosas más rápido y, a veces, cosas que no se pueden hacer de otras maneras. Es como la diferencia entre una pala y una excavadora. He escrito herramientas controladas por script para varias plataformas para leer archivos de entrada de texto y actualizar datos con operaciones de bajo nivel. Escribir una herramienta así también puede hacerte la vida más fácil (o al menos más interesante). Cosas como esta se pueden usar para modificar los datos de personalización en las instalaciones del cliente durante las actualizaciones de software.
0

He estado en esa situación. A veces tienes que hacerlo.

Algunos ORM permiten al desarrollador omitir el modelo de objetos e ir directamente a la capa de la base de datos.

También hay ORM, que utilizan operaciones masivas, encapsuladas, como orientadas a objetos.

umlcat
fuente
0

Como mencionó umlcat , hay algunos ORM que le permitirán usar operaciones masivas.

Aún mejor, muchos ORM son extensibles, por lo que puede escribir su propio método para ejecutar operaciones masivas, si aún no es compatible. Si la operación masiva en su aplicación es algo que puede factorizar, lo agregaría como una capa en el ORM (para hacer eso, probablemente necesite escribir SQL sin formato), pero luego en la aplicación, use el ORM Método que ha implementado.

Esto también facilita las pruebas unitarias y la depuración. Una vez que tenga una buena cobertura de prueba para sus métodos ORM, puede usarla libremente en sus aplicaciones. De lo contrario, la depuración de SQL sin formato (especialmente los grandes con transacciones y muchos JOIN) puede ser una molestia.

Una vez me llevó casi un día detectar un error en una llamada SQL sin procesar que era casi 100 LOC, ¡y el error era solo un carácter! Desde entonces, trato de evitar tener SQL sin procesar en la aplicación y hacer que todos los procedimientos de SQL se prueben por separado.

Atila O.
fuente
0

Bueno, no hay ningún patrón de diseño que yo sepa. Supongo que tomó la decisión del ORM por alguna razón, por lo que es probable que abandonar el ORM no sea lo que desea. Sin embargo, en estos casos creo que hay espacio para mezclar ambas soluciones. No hay nada de malo en eso, siempre que lo haga conscientemente y documente por qué se desvía del uso predeterminado del ORM en su software. Además de eso, algunos marcos ORM tienen algunas facilidades para realizar operaciones masivas. Sé que nHibernate (ORM para el marco .NET) se ha denominado StatelessSessions, que tienen muchos menos gastos generales, pero esto podría no darle el impulso de rendimiento que está buscando. En ese caso, solo use SQL sin formato.

Pieter
fuente