Log de sentencias SQL, sentencias lentas y otra información en jOOQ
Escrito por
el .
java
planeta-codigo
programacion
Enlace permanente
Comentarios
Algunas de las causas del bajo rendimiento de una aplicación que utiliza una base de datos son el número de sentencias que se realizan junto con las sentencias lentas por su coste de ejecución. Cada ejecución de una sentencia significa una comunicación por la red y ejecutar muchas de ellas significa un considerable y perceptible tiempo para el usuario. Por ello es conveniente saber que sentencias se ejecutan, si hay algún problema de 1+N o sentencias innecesarias que se repiten. Un log de las sentencias que se ejecutan es muy útil para detectar ineficiencias en la aplicación y corregirlas.
La librería jOOQ devuelve al lenguaje SQL de consultas para bases de datos relacionales al primer plano en una aplicación Java. En vez de crear una capa de abstracción como realiza la popular librería Hibernate del modelo relacional al modelo orientado a objetos de Java permite construir con un DSL mediante su API fluída avanzadas sentencias SQL que soportan las versiones recientes de PostgreSQL y MySQL.
En Hibernate la configuración de statistics, el logger org.hibernate.SQL y con el parámetro show_sql permiten visualizar que sentencias SQL se están lanzando, útil para conocer si algún problema de 1+N al navegar relaciones que ocasionalmente se producen si no son tenidas en cuenta. Además de que sentencias se están lanzando es también interesante conocer que tiempo de ejecución está tomando cada sentencia para conseguir que el rendimiento de la aplicación no sea lento, para detectar sentencias lentas.
Usando Spring Boot y la dependencia de jOOQ hay que proporcionar una instancia que implemente la interfaz ExecuteListener o crear una instancia de DefaultExecuteListener. Esta clase contiene numerosos métodos que permiten conocer y realizar acciones, en este caso emitir trazas. Dos de los métodos son executeStart() y executeEnd() invocados por jOOQ antes y después de cada sentencia que lanza. Usando System.nanoTime() se mide el tiempo de ejecución.
|
|
|
|
En las siguientes trazas de ejecución de sentencias se observa una inserción de un registro (1), una posterior muestra del listado para lo que se realizan dos sentencias una que cuenta el número de elementos en la tabla con un select count(*) que junto con el número de elementos por página permite conocer cuantas páginas hay y un select con un limit ? para recuperar los datos de la primera página (2). Con el suficiente número de elementos en la tabla se hace una consulta con un limit ? y un offset ? para los elementos de una página posterior a la primera (3). Al eliminar un elemento de la tabla se ejecuta una sentencia delete con el identificativo de la fila a eliminar en la clausula where (4), finalmente si se utiliza el botón Eliminar todos se elimina todas las filas con otra sentencia delete pero sin especificar la clausula where (5). En cada sentencia se muestra el tiempo que ha tardado.
Estas sentencias se ejecutan en unos pocos milisegundos, en una aplicación con tablas de algún millón de registros, varios joins, condiciones where complejas, ordenación y paginación las sentencias SQL pueden tardar varias segundos y decenas de segundos, conocer sus tiempos de ejecución es importante.
|
|
La clase ExecuteContext proporciona numerosa información sobre la ejecución de la sentencia como número de filas afectadas, si se ha producido una excepción, el tipo de sentencia (READ, WRITE, DDL, BATCH, ROUTINE u OTHER), sentencias batch u obtener los parámetros a través del objeto Query.
Simplemente mostrando las trazas de sentencias me ha permitido detectar que en el ejemplo se estaba realizando una pequeña ineficiencia. La sentencia select count(*) se lanzaba dos veces en la página de listado, una al querer saber si hay alguna fila y otra usada por el componente Grid de Tapestry. Para resolverlo se cachea el resultado en la clase anónima JooqGridDataSource con el siguiente código.
|
|
Las bases de datos MySQL y PostgreSQL también ofrecen la posibilidad de emitir en las sentencias en un log incluidas las sentencias lentas. Otra posibilidad es resaltar la sintaxis de las sentencias en la salida a la terminal para una mejor lectura dando color a las palabras claves.
El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:./gradlew run