JDBC Profiling with VisualVM

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

Introduction

In this article, we are going to see how we can do JDBC profiling using the VisualVM tool to find slow-running SQL queries or discover N+1 query issues.

VisualVM

VisualVM is an OSS tool that allows us to inspect the JVM and the Java applications running inside the Java Virtual Machine.

You can download VisualVM from this link and install it on your system. After installing it, you just need to run the following executable:

> bin/visualvm

And you will get information about the Java applications that are currently running on your system:

VisualVM

Notice that we can see information about CPU usage, memory allocation, thread, or class loading information.

However, there’s much more you can do with VisualVM than just monitoring the resources consumed by your Java application.

JDBC Profiling with VisualVM

If you go to the Profile tab and click the JDBC button, you can start the JDBC profiling, which will capture the SQL statements that are executed, as illustrated by the following screenshot:

JDBC Profiling with VisualVM

The SQL statements are ordered by the execution time in descending order, so the first ones are the long-running queries you might want to investigate.

If you click on an SQL statement, you will get the Java stack trace that generated the query:

VisualVM JDBC statement stack trace

Knowing the stack trace of a given SQL query can be very useful as you can easily spot the service method where the query in question originated.

To spot N+1 query issues, you just have to look for queries that initialize a single entity or collection by a given parent entity identifier, as illustrated by the following screenshot:

VisualVM JDBC Profiling N+1 query issue

The reason why we got this N+1 query issue in this Spring PetClinic
application is due to the implicit and explicit FetchType.EAGER associations contained in the Pet parent entity:

@Entity
@Table(name = "pets")
public class Pet extends NamedEntity {

    @Column(name = "birth_date")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthDate;

    @ManyToOne
    @JoinColumn(name = "type_id")
    private PetType type;

    @ManyToOne
    @JoinColumn(name = "owner_id")
    private Owner owner;

    @OneToMany(
        cascade = CascadeType.ALL, 
        mappedBy = "petId", 
        fetch = FetchType.EAGER
    )
    private Set<Visit> visits = new LinkedHashSet<>();    
}

In our case, the Pet entity was fetched by this entity query that you can spot as the first query in the previous JDBC profile screenshots:

select distinct 
    owner0_.id as id1_0_0_, 
    pets1_.id as id1_1_1_, 
    owner0_.first_name as first_na2_0_0_, 
    owner0_.last_name as last_nam3_0_0_, 
    owner0_.address as address4_0_0_, 
    owner0_.city as city5_0_0_, 
    owner0_.telephone as telephon6_0_0_, 
    pets1_.name as name2_1_1_, 
    pets1_.birth_date as birth_da3_1_1_, 
    pets1_.owner_id as owner_id4_1_1_, 
    pets1_.type_id as type_id5_1_1_, 
    pets1_.owner_id as owner_id4_1_0__, 
    pets1_.id as id1_1_0__ 
from 
    owners owner0_ 
left outer join 
    pets pets1_ on owner0_.id=pets1_.owner_id 
where 
    owner0_.last_name like '%'

Because the Pet entity is fetched without also fetching all its FetchType.EAGER associations, Hibernate has to resort to secondary queries that cause the N+1 query issues.

For more details about why FetchType.EAGER is a terrible mapping mistake, check out this article.

I'm running an online workshop on the 20-21 and 23-24 of November about High-Performance Java Persistence.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

VisualVM is a wonderful tool for monitoring application performance, and its JDBC profiling capabilities can be very handy.

Because we can spot both long-running entity queries and N+1 query issues, you might want to give this tool a try and make sure you discover such issues long before they affect the users of your application.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.