A Guide to Logging SQL Queries in Hibernate

Robert NiestrojRobert Niestroj
6 min read

show-sql=true

show-sql is the basic option in Hibernate to display the generated SQL Statements. It does print the statements to the console, so it is only a viable option if you analyze the output generated by Hibernate on a developer machine in an IDE or Terminal. It is not suited for production and big amounts of logs.

Since Hibernate works with prepared SQL Statements you won't see the actual parameter values. Most of the time for performance analysis this is OK. When it comes down to performance it's more important to know how much queries are executed, how do they look like, what columns they select from what tables, what are the joins and the WHERE clause. If we fetch a BankAccount with an IBAN X or Y most of the times this does not matter.

logging.level.org.hibernate.SQL=DEBUG

The alternative to show-sql is logging SQL Statement using a logging framework. By setting logging.level.org.hibernate.SQL (in Spring Boot) to DEBUG we get the same output as with show-sql, but the output is written to the console as well as to the file and other logging destinations depending on our logging configuration.

So for the following JPQL Query:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface BankAccountRepository extends JpaRepository<BankAccount, Long>{

    @Query(value = "Select b From BankAccount b where b.iban = :iban")
    List<BankAccount> findAllBankAccountsByIban(String iban);

}

the output will be something like:

select ba1_0.id,ba1_0.bic,ba1_0.iban from bank_account ba1_0 where ba1_0.iban=?

format-sql=true

While show-sql will show you the SQL Query, it will do so in one line, which for bigger queries makes it hard to read. That's why you should enable format-sql to see nicely formatted SQL Queries. The same formatting will be applied to queries logged by the logging framework.

    select
        ba1_0.id,
        ba1_0.bic,
        ba1_0.iban
    from
        bank_account ba1_0
    where
        ba1_0.iban=?

highlight-sql=true

If you decide to look at your queries in a terminal which supports coloring this option will color the SQL keywords. Do not use this if you log to a file. If you do so you’ll see markers which are responsible for coloring the output in a terminal which support coloring.

    select
        ba1_0.id,
        ba1_0.bic,
        ba1_0.iban
    from
        bank_account ba1_0
    where
        ba1_0.iban=?

use_sql_comments=true

If you find some SQL Queries which you'd like to optimize you need to know what generated them. Usually it originates from a JPQL Query or Criteria Query or something like that. Sometimes it easy to find the (source) JPQL Query based on the first table in the FROM clause and the WHERE clause. Sometimes it's harder. In order to find it quickly without guessing use_sql_comments logs the JPQL Query which generated the SQL Statements and you'll easily know which query to optimize.

    /* Select
        b
    From
        BankAccount b
    where
        b.iban = :iban */ select
            ba1_0.id,
            ba1_0.bic,
            ba1_0.iban
        from
            bank_account ba1_0
        where
            ba1_0.iban=?

@Meta

Spring Data JPA allows you to put custom comments on JPQL Queries. This is done using the @Meta annotation.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Meta;
import org.springframework.data.jpa.repository.Query;

public interface BankAccountRepository extends JpaRepository<BankAccount, Long>{

    @Meta(comment = "Important Query to keep an eye on")
    @Query(value = "Select b From BankAccount b where b.iban = :iban")
    List<BankAccount> findAllBankAccountsByIban(String iban);

}

The above Query, with the @Meta annotation will log the following statement:

    /* Important Query to keep an eye
        on */ select
            ba1_0.id,
            ba1_0.bic,
            ba1_0.iban
    from
        bank_account ba1_0
    where
        ba1_0.iban=?

generate_statistics=true

A useful thing to enable when analyzing the performance of Hibernate queries is generate_statistics. It shows you a few time based stats like how long it too to prepare and execute the query. It also shows you how many SQL Queries were generated for a given JPQL Query. It's important to know that one JPQL Query can result in many SQL Queries for example if you stumble on the N+1 problem. Hence a JPQL query not neccesarily translates into one SQL Query. If you find a case where you have multiple SQL queries for one JPQL Query it's often a sign that it can (or should) be optimized.

My personal pain-point with this is that the times are printed in nanoseconds. Mili- or microseconds would be easier to read by humans.

2024-09-23T22:45:46.250+02:00 DEBUG 14068 --- [jpa-tests] [  restartedMain] org.hibernate.SQL                        : 
    /* Select
        b
    From
        BankAccount b
    where
        b.iban = :iban */ select
            ba1_0.id,
            ba1_0.bic,
            ba1_0.iban
        from
            bank_account ba1_0
        where
            ba1_0.iban=?
2024-09-23T22:45:46.268+02:00  INFO 14068 --- [jpa-tests] [  restartedMain] i.StatisticalLoggingSessionEventListener : Session Metrics {
    1022900 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    9869200 nanoseconds spent preparing 1 JDBC statements;
    2443100 nanoseconds spent executing 1 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    0 nanoseconds spent executing 0 pre-partial-flushes;
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

Hibernate Slow Query Log

All previous points should not be used it production because it can easily flood your logs. They are intended for local development where you investigate a performance problem and can narrow it down to a action in your system or a test case. What you can enable in production however is Hibernates Slow Query Log. It allows you to specify a threshold in milliseconds and when an SQL Query takes longer to execute then this threshold it will be logged and you have a candidate for optimization.

The Spring Boot configuration for the Slow query log needs the threshold set and the log level to info:

spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=1

logging.level.org.hibernate.SQL_SLOW=info

By default only the prepared statement will be logged.

2024-09-23T23:00:48.398+02:00  INFO 17048 --- [jpa-coaching] [  restartedMain] org.hibernate.SQL_SLOW                   : Slow query took 4 milliseconds [select ba1_0.id,ba1_0.bic,ba1_0.iban from bank_account ba1_0 where ba1_0.iban=?]

If you have use_sql_comments enabled also the JPQL Query will be logged:

2024-09-23T22:56:16.351+02:00  INFO 14068 --- [jpa-coaching] [  restartedMain] org.hibernate.SQL_SLOW                   : Slow query took 2 milliseconds [/* Select b From BankAccount b where b.iban = :iban */ select ba1_0.id,ba1_0.bic,ba1_0.iban from bank_account ba1_0 where ba1_0.iban=?]

VisualVM JDBC Monitoring

If you want to get an birds-eye-view of what is going in your application and query logging like above logs too much a good option to use i VisualVM. VisualVM on itself it s profiler - a tool to analyze performance of JVM applications. However a special feature of VisualVM is JDBC Monitoring. It captures all SQL which went through JDBC, so not only SQL statements generated by Hibernate. It will show all the queries with their number of executions. Then you can sort it by this execution count and so you can look if some queries are executed more times then you'd expect it.

Summary

Logging the SQL queries generated by Hibernate is the best way to analyze performance problems. With the settings mentioned above, you'll get a clear overview of what needs to be optimized to improve the database performance of your app.

0
Subscribe to my newsletter

Read articles from Robert Niestroj directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Robert Niestroj
Robert Niestroj

Software Developer doing Java, JavaScript for over 10 years. Working in Polish and German projects.