mssql java mysql performance hibernate jdbc

java - mssql - sql jdbc jar



Rendimiento de Hibernate, JDBC y Java en conjuntos de resultados medianos y grandes (1)

¿Puedes hacer una prueba de humo con la simple consulta posible como:

SELECT current_timestamp()

o

SELECT 1 + 1

Esto le dirá cuál es la sobrecarga real del controlador JDBC. Tampoco está claro si ambas pruebas se realizan desde la misma máquina.

¿Hay una manera de optimizar el rendimiento del controlador JDBC?

Ejecute la misma consulta varios miles de veces en Java. La JVM necesita algo de tiempo para calentarse (carga de clase, JIT). También supongo que SimpleJDBC.getConnection() utiliza la agrupación de conexiones C3P0: el costo de establecer una conexión es bastante alto, por lo que la primera ejecución podría ser lenta.

También prefiera consultas nombradas a consultas ad-hoc o consultas de criterios.

¿Y Hibernate beneficiará esta optimización?

Hibernate es un marco muy complejo. Como puede ver, consume el 75% del tiempo total de ejecución en comparación con el JDBC sin procesar. Si necesita ORM sin procesar (sin carga mybatis , comprobación sucia, almacenamiento en caché avanzado), considere mybatis . O tal vez incluso JdbcTemplate con la abstracción RowMapper .

¿Hay alguna forma de optimizar el rendimiento de Hibernate al convertir conjuntos de resultados?

Realmente no. Consulte el Capítulo 19. Mejora del rendimiento en la documentación de Hibernate. Hay mucha reflexión pasando por ahí + generación de clase. Una vez más, es posible que Hibernate no sea la mejor solución cuando desee exprimir cada milisegundo de su base de datos.

Sin embargo , es una buena opción cuando desea aumentar la experiencia general del usuario debido al amplio soporte de almacenamiento en caché. Echa un vistazo a la documentación de rendimiento de nuevo. En su mayoría habla de almacenamiento en caché. Hay una memoria caché de primer nivel, una memoria caché de segundo nivel, una memoria caché de consulta ... Este es el lugar donde Hibernate podría realmente superar a JDBC simple: puede almacenar mucha memoria caché de una forma que ni siquiera podría imaginar. Por otro lado, una configuración de caché deficiente podría llevar a una configuración aún más lenta.

Echa un vistazo a: Caché con Hibernate + Spring - ¡Algunas preguntas!

¿Estamos frente a algo que no se puede ajustar debido a la gestión de memoria y objeto fundamental de Java?

JVM (especialmente en la configuración del servidor ) es bastante rápido. La creación de objetos en el montón es tan rápida como en la pila, por ejemplo, en C, la recolección de basura se ha optimizado en gran medida. No creo que la versión Java que ejecuta JDBC sea mucho más lenta en comparación con una conexión más nativa. Es por eso que sugerí algunas mejoras en su punto de referencia.

¿Estamos perdiendo un punto, somos estúpidos y todo esto es vano?

Creo que JDBC es una buena opción si el rendimiento es su mayor problema. Java se ha utilizado con éxito en muchas aplicaciones de bases de datos.

Problema

Estamos tratando de optimizar nuestra aplicación de servidor de datos. Almacena acciones y cotizaciones sobre una base de datos mysql. Y no estamos satisfechos con las actuaciones de captación.

Contexto

- database - table stock : around 500 lines - table quote : 3 000 000 to 10 000 000 lines - one-to-many association : one stock owns n quotes - fetching around 1000 quotes per request - there is an index on (stockId,date) in the quote table - no cache, because in production, querys are always different - Hibernate 3 - mysql 5.5 - Java 6 - JDBC mysql Connector 5.1.13 - c3p0 pooling

Pruebas y resultados

Protocolo

  • Los tiempos de ejecución en el servidor mysql se obtienen al ejecutar las consultas de SQL generadas en la línea de comandos mysql.
  • El servidor está en un contexto de prueba: no hay otras lecturas de DB, no hay escrituras de DB
  • Obtenemos 857 cotizaciones para el stock de AAPL.

Caso 1: Hibernar con asociación.

Esto llena nuestro objeto de stock con 857 comillas objeto (todo correctamente asignado en hibernate.xml)

session.enableFilter("after").setParameter("after", 1322910573000L); Stock stock = (Stock) session.createCriteria(Stock.class). add(Restrictions.eq("stockId", stockId)). setFetchMode("quotes", FetchMode.JOIN).uniqueResult();

SQL generado:

SELECT this_.stockId AS stockId1_1_, this_.symbol AS symbol1_1_, this_.name AS name1_1_, quotes2_.stockId AS stockId1_3_, quotes2_.quoteId AS quoteId3_, quotes2_.quoteId AS quoteId0_0_, quotes2_.value AS value0_0_, quotes2_.stockId AS stockId0_0_, quotes2_.volume AS volume0_0_, quotes2_.quality AS quality0_0_, quotes2_.date AS date0_0_, quotes2_.createdDate AS createdD7_0_0_, quotes2_.fetcher AS fetcher0_0_ FROM stock this_ LEFT OUTER JOIN quote quotes2_ ON this_.stockId=quotes2_.stockId AND quotes2_.date > 1322910573000 WHERE this_.stockId=''AAPL'' ORDER BY quotes2_.date ASC

Resultados:

  • Tiempo de ejecución en el servidor mysql: ~ 10 ms
  • Tiempo de ejecución en Java: ~ 400ms

Caso 2: Hibernar sin asociación sin HQL

Pensando en aumentar el rendimiento, hemos utilizado ese código que solo recupera los objetos de cotizaciones y los agregamos manualmente a un stock (por lo que no obtenemos información repetida sobre el stock para cada línea). Utilizamos createSQLQuery para minimizar los efectos de los alias y el desorden HQL.

String filter = " AND q.date>1322910573000"; filter += " ORDER BY q.date DESC"; Stock stock = new Stock(stockId); stock.addQuotes((ArrayList<Quote>) session.createSQLQuery("select * from quote q where stockId=''" + stockId + "'' " + filter).addEntity(Quote.class).list());

SQL generado:

SELECT * FROM quote q WHERE stockId=''AAPL'' AND q.date>1322910573000 ORDER BY q.date ASC

Resultados:

  • Tiempo de ejecución en el servidor mysql: ~ 10 ms
  • Tiempo de ejecución en Java: ~ 370ms

Caso 3: JDBC sin hibernación

String filter = " AND q.date>1322910573000"; filter += " ORDER BY q.date DESC"; Stock stock = new Stock(stockId); Connection conn = SimpleJDBC.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from quote q where stockId=''" + stockId + "'' " + filter); while(rs.next()) { stock.addQuote(new Quote(rs.getInt("volume"), rs.getLong("date"), rs.getFloat("value"), rs.getByte("fetcher"))); } stmt.close(); conn.close();

Resultados:

  • Tiempo de ejecución en el servidor mysql: ~ 10 ms
  • Tiempo de ejecución en Java: ~ 100ms

Nuestros entendimientos

  • El driver JDBC es común a todos los casos.
  • Hay un costo de tiempo fundamental en la conducción JDBC
  • Con consultas de SQL similares, Hibernate pasa más tiempo que el código JDBC puro para convertir conjuntos de resultados en objetos
  • Hibernate createCriteria, createSQLQuery o createQuery son similares en costo de tiempo
  • En la producción, donde tenemos mucha escritura simultánea, la solución JDBC pura parecía ser más lenta que la de hibernación (tal vez porque nuestras soluciones JDBC no estaban agrupadas)
  • Mysql sabio, el servidor parece comportarse muy bien, y el coste del tiempo es muy aceptable

Nuestras preguntas

  • ¿Hay una manera de optimizar el rendimiento del controlador JDBC?
  • ¿Y Hibernate beneficiará esta optimización?
  • ¿Hay alguna forma de optimizar el rendimiento de Hibernate al convertir conjuntos de resultados?
  • ¿Estamos frente a algo que no se puede ajustar debido a la gestión de memoria y objeto fundamental de Java?
  • ¿Estamos perdiendo un punto, somos estúpidos y todo esto es vano?
  • ¿Somos franceses? Sí.

Su ayuda es muy bienvenida.