2008-09-15 42 views

Respuesta

49

El primer y más dramático problema de rendimiento que puede encontrarse con NHibernate es si está creando una nueva fábrica de sesiones para cada sesión que cree. Solo se debe crear una instancia de fábrica de sesión para cada ejecución de la aplicación y esa fábrica debe crear todas las sesiones.

En esta línea, debe continuar utilizando la misma sesión, siempre que tenga sentido. Esto variará según la aplicación, pero para la mayoría de las aplicaciones web, se recomienda una sola sesión por solicitud. Si descarta su sesión con frecuencia, no está obteniendo los beneficios de su caché. El uso inteligente de la memoria caché de la sesión puede cambiar una rutina con un número lineal (o peor) de consultas a un número constante sin mucho trabajo.

Igual de importante es que quiere asegurarse de que es perezoso cargar sus referencias de objeto. Si no lo está, se podrían cargar gráficos completos de objetos incluso para las consultas más simples. Solo hay ciertas razones para no hacerlo, pero siempre es mejor comenzar con la carga diferida y volver a cambiar según sea necesario.

Eso nos lleva a la búsqueda ansiosa, lo contrario de la carga perezosa. Mientras recorre las jerarquías de objetos o recorre las colecciones, puede ser fácil perder el registro de la cantidad de consultas que realiza y termina con un número exponencial de consultas. La obtención con ganas se puede hacer por consulta con un FETCH JOIN. En circunstancias excepcionales, como si hay un par de tablas en particular que siempre busca unirse, considere desactivar la carga diferida para esa relación.

Como siempre, el Analizador de SQL es una excelente forma de encontrar consultas que se ejecutan lentamente o se realizan de forma repetida. En mi último trabajo, teníamos una función de desarrollo que contabilizaba consultas por solicitud de página también. Una gran cantidad de consultas para una rutina es el indicador más obvio de que su rutina no está funcionando bien con NHibernate. Si el número de consultas por rutina o solicitud se ve bien, probablemente no tenga que ajustar la base de datos; asegurándose de tener suficiente memoria para almacenar los planes de ejecución y los datos en la caché, indexando correctamente sus datos, etc.

Un pequeño y delicado problema con el que nos encontramos fue con SetParameterList(). La función le permite pasar fácilmente una lista de parámetros a una consulta. NHibernate lo implementó al crear un parámetro para cada elemento pasado. Esto da como resultado un plan de consulta diferente para cada número de parámetros. Nuestros planes de ejecución casi siempre fueron liberados del caché. Además, numerosos parámetros pueden ralentizar significativamente una consulta. Hicimos un truco personalizado de NHibernate para enviar los elementos como una lista delimitada en un solo parámetro. La lista estaba separada en SQL Server por una función de valor de tabla que nuestro hack insertó automáticamente en la cláusula IN de la consulta. Podría haber otras minas terrestres como esta dependiendo de su aplicación. SQL Profiler es la mejor manera de encontrarlos.

+1

es NH no perezoso referencias de objetos de carga por defecto? Si no, ¿qué haces para forzar esto? – sydneyos

+0

@sydneyos Si está utilizando Fluent NHibernate, puede agregar DefaultLazy.Always() como convención a su configuración Fluent NHibernate. No estoy seguro de cómo funciona con las asignaciones de .hbm, pero imagino que puede agregar eso bastante fácilmente en la configuración de NH. – Anshul

4

Sin ningún tipo de detalles sobre los tipos de problemas de rendimiento que está viendo, solo puedo ofrecer una generalización: En mi experiencia, la mayoría de los problemas de rendimiento de las consultas de bases de datos surgen de la falta de índices adecuados. Así que mi sugerencia para una primera acción sería verificar sus planes de consulta para consultas no indexadas.

3

NHibernate genera SQL bastante rápido nada más sacarlo de la caja. Lo he estado utilizando durante un año, y aún tengo que escribir SQL desnudo con él. Todos mis problemas de rendimiento han sido desde Normalization y falta de índices.

La solución más fácil es examinar los planes de ejecución de sus consultas y crear índices adecuados, especialmente en sus columnas de clave externa. Si está utilizando Microsoft SQL Server, el "Asesor de ajuste de motor de base de datos" ayuda mucho con esto.

1

Si aún no está utilizando la carga diferida (apropiadamente), comience. Obtener colecciones cuando no las necesitas es un desperdicio de todo.

Chapter Improving performance describe esta y otras formas de mejorar el rendimiento.

1

de perfiles es el primer paso - unidad de pruebas cronometradas incluso simples - para averiguar dónde las mayores ganancias se pueden hacer

Para colecciones considerar ajustar el tamaño del lote para reducir el número de sentencias de selección emitidas - véase la sección Improving performance de detalles

1

¿Solo puedo limitar mi respuesta a una opción? En ese caso, seleccionaría que implemente el mecanismo de caché de segundo nivel de NHibernate.

De esta manera, para cada objeto en su archivo de mapeo usted puede definir la estrategia de caché. La memoria caché de segundo nivel mantendrá los objetos ya recuperados en la memoria y, por lo tanto, no realizará otra ida y vuelta a la base de datos. Este es un gran refuerzo de rendimiento.

Su objetivo es definir los objetos a los que accede constantemente su aplicación. Entre ellos habrá ajustes generales y similares.

Hay mucha información para encontrar la memoria caché de segundo nivel nhibernate y cómo implementarla.

Buena suerte :)

1

almacenamiento en caché, almacenamiento en caché, almacenamiento en caché - ¿Está utilizando su primera caché de nivel correctamente [sesiones de cierre antes de tiempo, o el uso de StatelessSession para eludir primer nivel de almacenamiento en caché]? ¿Necesita configurar un caché de segundo nivel simple para valores que cambian con poca frecuencia? ¿Puede guardar en caché los conjuntos de resultados de las consultas para acelerar las consultas que cambian con poca frecuencia?

[También configuración: ¿puede establecer elementos como inmutables? ¿Puede reestructurar consultas para recuperar solo la información que necesita y transformarla en la entidad original? ¿Podrá Batman detener al Acertijo antes de llegar a la presa? ... oh, lo siento se dejó llevar]

25

SessionFactory de NHibernate es una operación costosa por lo que una buena estrategia es la que crea un Singleton asegura que no es sólo una instancia de SessionFactory en la memoria:.

public class NHibernateSessionManager 
    { 
     private readonly ISessionFactory _sessionFactory; 

     public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager(); 

     private NHibernateSessionManager() 
     { 
      if (_sessionFactory == null) 
      { 
       System.Diagnostics.Debug.WriteLine("Factory was null - creating one"); 
       _sessionFactory = (new Configuration().Configure().BuildSessionFactory()); 
      } 
     } 

     public ISession GetSession() 
     { 
      return _sessionFactory.OpenSession(); 
     } 

     public void Initialize() 
     { 
      ISession disposeMe = Instance.GetSession(); 
     } 
    } 

Luego, en el Global.asax Application_Startup, puede inicializarlo:

protected void Application_Start() 
{ 
    NHibernateSessionManager.Instance.Initialize(); 
} 
+0

+1 para proporcionar un ejemplo de trabajo simple y explicación. ¡Ojalá hubiera habido una función para dar más de 1 por una buena respuesta! –

11

evitar y/o minimizar la Select N + 1 problem mediante el reconocimiento de cuándo cambiar de carga diferida para ir a buscar ávido de consultas lentas rendimiento.

+0

No estoy de acuerdo con la solución. Mantenga la carga lenta, pero habilite [búsqueda por lotes] (http://nhibernate.info/doc/nhibernate-reference/performance.html#performance-fetching-batch) de carga lenta. Esto elimina el problema de N + 1 con un impacto mínimo en el código. He escrito más sobre esto en mi respuesta a otra pregunta [aquí] (/ a/36070727/1178314). –

10

No es una recomendación, pero una herramienta para ayudarlo: NH Prof (http://nhprof.com/) parece ser prometedor, puede evaluar su uso del marco ORM. Puede ser un buen punto de partida para su ajuste de NHibernate.

+0

Sí. Haz que funcione, ENTONCES haz que funcione rápido. Y un perfilador como NH Prof puede mostrarle los cuellos de botella. –

0

Lo que lotsoffreetime dijo.

Lea el Capítulo 19 de la documentación, "Mejora del rendimiento".
NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
Hibernate: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

Uso de SQL (o equivalente para la base de datos que está utilizando) para localizar consultas de larga duración. Optimice esas consultas con los índices apropiados.

Para las llamadas a la base de datos utilizadas en casi todas las páginas de una aplicación, use CreateMultiQuery para devolver múltiples resultados desde una sola consulta de base de datos.

Y por supuesto, caché. La directiva OutputCache para páginas/controles. Almacenamiento en caché de NHibernate para datos.

+0

Ese enlace ya no funciona, ¿alguien tiene un enlace actualizado? – sydneyos

3

"Una recomendación por respuesta" solamente? Entonces me gustaría ir a este:

Evite juntar duplicados (AKA productos cartesianos) debido a las uniones a lo largo de dos o más asociaciones paralelas a muchas; utilice Exists-subqueries, MultiQueries o FetchMode "subselect" en su lugar.

Tomado de: Hibernate Performance Tuning Tips

Cuestiones relacionadas