The Artima Developer Community
Sponsored Link

Java Buzz Forum
How to activate Hibernate Statistics to analyze performance issues

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Thorben Janssen

Posts: 44
Nickname: thjanssen
Registered: Jun, 2014

Thorben Janssen is a senior developer blogging about Java EE related topics.
How to activate Hibernate Statistics to analyze performance issues Posted: Mar 9, 2015 10:21 PM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Thorben Janssen.
Original Post: How to activate Hibernate Statistics to analyze performance issues
Feed Title: Thoughts on Java
Feed URL: http://www.thoughts-on-java.org/feeds/posts/default
Feed Description: Tutorials and howtos about Java and Java EE related topics.
Latest Java Buzz Posts
Latest Java Buzz Posts by Thorben Janssen
Latest Posts From Thoughts on Java

Advertisement
Did you ever ask yourself why a server request took ages on the production system while your local test system was just fine?
Well, we all had these situations and we will have several more of them in the future. In my experience, strange performance drops are often related to slow database queries. But which query causes the problem? And how to find it, if you can't or don't want to activate logging on your database?

The good news is, there is an easy way to do it. Hibernate can be configured to collect statistics and to provide the required information to analyze the database queries. So lets see what we need to do.




Demo application

Let's begin with a simple demo application. I know your production code is way more complex, but we only need a few database requests for our statistics. Therefore we will use a Product entity with an ID, a version and a name.
@Entity
public class Product implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id = null;

@Version
@Column(name = "version")
private int version = 0;

@Column
private String name;

...
}

We use this in a loop to store 10 records in the database and query them afterwards.
for (int i=0; i>10; i++) {
Product p = new Product();
p.setName("MyProduct"+i);
this.em.persist(p);
}

this.em.createQuery("Select p From Product p").getResultList();


Configuration

The first thing we need to do is tell Hibernate to generate statistics for us. Therefore we need to set the system property hibernate.generate_statistics to true. Statistics are deactivated by default because it has a bad influence on the performance. So only activate them when you need them.

Now Hibernate will write one multi-line log statement with summarized statistical information at the end of the session. This is quite useful to get an overview on how much time was spend on database communication. But in most cases we need more information. We need to know, if there was a specific query that took a long time or if we have an overall performance issue. Therefore we would like to log the execution time for each query. This can be done by setting the log level for org.hibernate.stat to DEBUG.

I used a Wildfly 8.1.0.Final application server with Hibernate 4.3.5 for this example and did the described configuration changes by adding the following lines to the standalone.xml file.
...
<system-properties>
<property name="hibernate.generate_statistics" value="true"/>
</system-properties>

...

<profile>
<subsystem xmlns="urn:jboss:domain:logging:2.0">

...
<logger category="org.hibernate.stat">
<level name="DEBUG"/>
</logger>

...

Log output

If we execute the test code to store 10 Product entities in the database and read them from the database afterwards, Hibernate writes the following log messages:
2015-03-03 20:28:52,484 DEBUG [org.hibernate.stat.internal.ConcurrentStatisticsImpl] (default task-1) HHH000117: HQL: Select p From Product p, time: 0ms, rows: 10
2015-03-03 20:28:52,484 INFO [org.hibernate.engine.internal.StatisticalLoggingSessionEventListener] (default task-1) Session Metrics {
8728028 nanoseconds spent acquiring 12 JDBC connections;
295527 nanoseconds spent releasing 12 JDBC connections;
12014439 nanoseconds spent preparing 21 JDBC statements;
5622686 nanoseconds spent executing 21 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;
403863 nanoseconds spent executing 1 flushes (flushing a total of 10 entities and 0 collections);
25529864 nanoseconds spent executing 1 partial-flushes (flushing a total of 10 entities and 10 collections)
}
As you can see, the specific statistics for the select statement and the overall session statistics were written to the log file.

The statistics of the select statement show the number or returned rows (10) and the execution time of the statement (0ms). This would be the place where we would identify a slow statement. But there is obviously no performance issue with this simple query ;-)

The overall statistics provide information about the number of used JDBC connections and statements, the cache usage and the performed flushes. Here you should always check the number of statements first. Lots of performance issues are caused by n+1 select issues that can result in lots of additional queries. You can find more information about how to fix these kind of issues here: 5 ways to initialize lazy relations and when to use them.

If you wonder why Hibernate used 21 instead of 11 JDBC statements to store 10 Product entities and read all of them afterwards, you need to set org.hibernate.SQL to DEBUG to get more information. Hibernate required 2 statements to store each new product in the database because it selected the ID of each entity from a database sequence first and used it to store a fully initialized entity in the database.

Conclusion

If you need to analyze performance issues, Hibernate can collect and log useful statistics about each database query and the whole session. This needs to be activated by setting the system property hibernate.generate_statistics to true and the log level for org.hibernate.stat to DEBUG.

You can then decide, if the performance issue is caused by the database communication or by some other part of the system. If it is caused by the database communication, you can see if you need to fix it in your Java code or if you need to contact your database administrator to get more detailed information about your slow queries.

You enjoyed this article and like to learn more about Java EE? Make sure to subscribe below or follow me on twitter and google+.

Read: How to activate Hibernate Statistics to analyze performance issues

Topic: Constructors in java Previous Topic   Next Topic Topic: This and Super Keywords

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use