A beginner’s guide to Hibernate Statistics
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
Hibernate provides a very powerful Statistics mechanism that, unfortunately, is lesser known. In this article, we are going to see how the Hibernate Statistics mechanism works, and how you can activate.
While the Hibernate Statistics mechanism is not enabled by default, you will see that many applications can benefit from using it, especially when it comes to determining cache effectiveness.
A beginner’s guide to Hibernate Statistics@vlad_mihalcea https://t.co/OdUcM0A74x pic.twitter.com/CNajj2H9xj
— Java (@java) May 1, 2019
Statistics interface
The Hibernate Statistics class hierarchy looks as follows:
The Hibernate org.hibernate.stat.Statistics
interface contains an exhaustive list of metrics you can inspect in regards to the behavior of the current Hibernate SessionFactory
or JPA EntityManager
.
General-purpose methods
The following Statistics
methods are used to describe or control the current Hibernate Statistics
object.
boolean isStatisticsEnabled()
- It determines whether the Hibernate statistic mechanism is enabled or not.
void setStatisticsEnabled(boolean b)
- It enables or disables the Hibernate Statistics mechanism.
void clear()
- It removes the current collected metrics.
long getStartTime()
- It gets the timestamp when the
Statistics
instance was instantiated. void logSummary()
- It prints a log entry containing the most important metrics.
EntityManager or Session metrics
The following metrics are associated with the current Persistence Context:
long getSessionOpenCount()
- It provides the number of
Session
orEntityManager
instances that were opened by the currentEntityManagerFactory
orSessionFactory
. long getSessionCloseCount()
- It provides the number of
Session
orEntityManager
instances that were closed by the currentEntityManagerFactory
orSessionFactory
. long getFlushCount()
- It provides the number of times the
Session
orEntityManager
instances were flushed.
Database metrics
The following metrics are associated with either the database connection, transaction or executing statements:
long getConnectCount()
- It gives the number of database connections that were acquired by the current
EntityManagerFactory
orSessionFactory
. long getSuccessfulTransactionCount()
- It gives the number of transactions that were committed by the current
EntityManagerFactory
orSessionFactory
. long getTransactionCount()
- It gives the number of transactions that were executed by the current
EntityManagerFactory
orSessionFactory
. long getPrepareStatementCount()
- It provides the number of JDBC
PreparedStatements
that were created by the currentEntityManagerFactory
orSessionFactory
. long getCloseStatementCount()
- It provides the number of JDBC statement instances that were closed by the current
EntityManagerFactory
orSessionFactory
.
Entity metrics
The following metrics are associated with the JPA or Hibernate entities:
String[] getEntityNames()
- It provides the names of all entities that are registered with the current
EntityManagerFactory
orSessionFactory
. EntityStatistics getEntityStatistics(String entityName)
- It provides you the
EntityStatistics
object for the provided entity name. long getEntityLoadCount()
- It gives you the total number of entities that were loaded (including the one fetched from the first or second-level cache or the database) by the current
EntityManagerFactory
orSessionFactory
. long getEntityFetchCount()
- It gives you the total number of entities that were fetched from the database by the current
EntityManagerFactory
orSessionFactory
. long getEntityInsertCount()
- It gives you the total number of entities that were inserted by the current
EntityManagerFactory
orSessionFactory
. long getEntityUpdateCount()
- It gives you the total number of entities that were updated by the current
EntityManagerFactory
orSessionFactory
. long getEntityDeleteCount()
- It gives you the total number of entities that were deleted by the current
EntityManagerFactory
orSessionFactory
.
Collection metrics
The following metrics are associated with the JPA or Hibernate entity collections:
String[] getCollectionRoleNames()
- It provides the names of all entity collections that are registered with the current
EntityManagerFactory
orSessionFactory
. CollectionStatistics getCollectionStatistics(String role)
- It provides you the
CollectionStatistics
object for the provided entity collection name. long getCollectionLoadCount()
- It gives you the total number of collections that were loaded (including the one fetched from the first or second-level cache or the database) by the current
EntityManagerFactory
orSessionFactory
. long getCollectionFetchCount()
- It gives you the total number of collections that were fetched from the database by the current
EntityManagerFactory
orSessionFactory
. long getCollectionUpdateCount()
- It gives you the total number of collections that were updated by the current
EntityManagerFactory
orSessionFactory
. long getCollectionRemoveCount()
- It gives you the total number of collections that were removed by the current
EntityManagerFactory
orSessionFactory
. long getCollectionRecreateCount()
- It gives you the total number of collections that were recreated by the current
EntityManagerFactory
orSessionFactory
.
Query metrics
The following metrics are associated with the queries that were executed by the current JPA EntityManagerFactory
or Hibernate SessionFactory
:
String[] getQueries()
- It returns the entity queries (e.g. HQL and Criteria API) executed by the current JPA
EntityManagerFactory
or HibernateSessionFactory
. QueryStatistics getQueryStatistics(String queryString)
- It returns the
QueryStatistics
associated to the provided query. long getQueryExecutionCount()
- It gives the number of queries that were executed by the current JPA
EntityManagerFactory
or HibernateSessionFactory
. long getQueryExecutionMaxTime()
- It gives the maximum execution time of all queries that were executed.
String getQueryExecutionMaxTimeQueryString()
- It gives the name of the query with the longest execution time.
long getQueryPlanCacheHitCount()
- It provides the hit count for the Query Plan Cache.
long getQueryPlanCacheMissCount()
- It provides the miss count for the Query Plan Cache.
Natural identifier metrics
The following metrics are associated with the Hibernate natural identifier mechanism:
NaturalIdStatistics getNaturalIdStatistics(String entityName)
- It returns the
NaturalIdStatistics
associated with the provided entity name. long getNaturalIdQueryExecutionCount()
- It gives the number of times a given entity identifier was resolved by its associated natural id.
long getNaturalIdQueryExecutionMaxTime()
- It gives the maximum execution time a given entity identifier was resolved by its associated natural id.
String getNaturalIdQueryExecutionMaxTimeRegion()
- It gives the second-level cache region name with the longest natural id resolving query.
String getNaturalIdQueryExecutionMaxTimeEntity()
- It gives the entity name for whichthe longest natural id resolving query was recorded.
Second-level cache metrics
The following metrics are associated with the second-level caching mechanism:
String[] getSecondLevelCacheRegionNames()
- It provides the names of all regions used by the second-level cache.
CacheRegionStatistics getDomainDataRegionStatistics(String regionName)
- It provides the
CacheRegionStatistics
associated with the given region name. CacheRegionStatistics getQueryRegionStatistics(String regionName)
- It provides the query
CacheRegionStatistics
associated with the given region name. CacheRegionStatistics getCacheRegionStatistics(String regionName)
- It provides the domain data or query
CacheRegionStatistics
associated with the given region name. long getSecondLevelCacheHitCount()
- It provides the global hit count of all entity or collection cache regions.
long getSecondLevelCacheMissCount()
- It provides the global miss count of all entity or collection cache regions.
long getSecondLevelCachePutCount()
- It provides the global put count of all entity or collection cache regions.
long getNaturalIdCacheHitCount()
- It provides the global hit count of the natural id cache region.
long getNaturalIdCacheMissCount()
- It provides the global miss count of the natural id cache region.
long getNaturalIdCachePutCount()
- It provides the global put count of the natural id cache region.
long getQueryCacheHitCount()
- It provides the hit count of the query cache region.
long getQueryCacheMissCount()
- It provides the miss count of the query cache region.
long getQueryCachePutCount()
- It provides the put count of the query cache region.
long getUpdateTimestampsCacheHitCount()
- It provides the hit count of the timestamp cache region, which is used by the query cache.
long getUpdateTimestampsCacheMissCount()
- It the miss count of the timestamp cache region, which is used by the query cache.
long getUpdateTimestampsCachePutCount()
- It provides the global put count of the timestamp cache region, which is used by the query cache.
Concurrency-control metrics
long getOptimisticFailureCount()
- It provides the number of optimistic locking failures detected by the current
EntityManagerFactory
orSessionFactory
.
StatisticsImplementor interface
The org.hibernate.stat.spi.StatisticsImplementor
interface extends the aforementioned Statistics
interface and defines multiple callback methods that are executed by the Hibernate core API.
EntityManager or Session metrics
void openSession()
- This callback is called when a JPA
EntityManager
or the HibernateSession
is created. void closeSession()
- This callback is called when a JPA
EntityManager
or the HibernateSession
is closed. void flush()
- This callback is called when a JPA
EntityManager
or the HibernateSession
is flushed.
Database metrics
void connect()
- This callback is called when a database connection is acquired from the currently configured
ConnectionProvider
. void prepareStatement()
- This callback is called when a JDBC
PreparedStatement
instance is created. void closeStatement()
- This callback is called when a JDBC
PreparedStatement
instance is closed. void endTransaction(boolean success)
- This callback is called when the RESOURCE_LOCAL or JTA transaction is either committed or rolled back.
Entity metrics
void loadEntity(String entityName)
- This callback is called when a given entity is loaded either as a Proxy or by fetching it from the database.
void fetchEntity(String entityName)
- This callback is called when a given entity is fetched from the database.
void insertEntity(String entityName)
- This callback is called when a given entity is inserted.
void updateEntity(String entityName)
- This callback is called when a given entity is updated.
void deleteEntity(String entityName)
- This callback is called when a given entity is deleted.
Collection metrics
void loadCollection(String role)
- This callback is executed when a given entity collection is either created or loaded.
void fetchCollection(String role)
- This callback is executed when a given entity collection is fetched from the database.
void updateCollection(String role)
- This callback is executed when a given entity collection is updated.
void recreateCollection(String role)
- This callback is executed when a given entity collection is recreated.
void removeCollection(String role)
- This callback is executed when a given entity collection is removed.
Query metrics
void queryExecuted(String hql, int rows, long time)
- This callback is called after an entity or native SQL query is executed.
void queryPlanCacheHit(String hql)
- This callback is called when the entity query plan was loaded from the query plan cache.
void queryCompiled(String hql, long microseconds)
- This callback is called when the entity query plan could not be loaded from the query plan cache.
Second-level cache metrics
void entityCachePut(NavigableRole entityName, String regionName)
- This callback is executed when a given entity is added to the second-level cached.
void entityCacheHit(NavigableRole entityName, String regionName)
- This callback is executed when a given entity is loaded from the second-level cached.
void entityCacheMiss(NavigableRole entityName, String regionName)
- This callback is executed when a given entity was not found in the second-level cached.
void collectionCachePut(NavigableRole collectionRole, String regionName)
- This callback is executed when a given entity collection was added to the second-level cached.
void collectionCacheHit(NavigableRole collectionRole, String regionName)
- This callback is executed when a given entity collection is loaded from the second-level cached.
void collectionCacheMiss(NavigableRole collectionRole, String regionName)
- This callback is executed when a given entity collection was not found in the second-level cached.
void naturalIdCachePut(NavigableRole rootEntityName, String regionName)
- This callback is executed when a given natural id is added to the second-level cached.
void naturalIdCacheHit(NavigableRole rootEntityName, String regionName)
- This callback is executed when a given entity identifier is resolved via its associated natural id from the second-level cached.
void naturalIdCacheMiss(NavigableRole rootEntityName, String regionName)
- This callback is executed when a given entity identifier could not be resolved via its associated natural id from the second-level cached.
void naturalIdQueryExecuted(String rootEntityName, long executionTime)
- This callback is called after the entity identifier query by the associated natural id is executed.
void queryCachePut(String hql, String regionName)
- This callback is called when a query cache entry is stored in the second-level query cache region.
void queryCacheHit(String hql, String regionName)
- This callback is called when a query cache entry is loaded from the second-level query cache region.
void queryCacheMiss(String hql, String regionName)
- This callback is called when a query cache entry could not be loaded from the second-level query cache region.
void updateTimestampsCacheHit()
- This callback is called when the tablespace last update timestamp is loaded from the timestamp query cache region
void updateTimestampsCacheMiss()
- This callback is called when the tablespace last update timestamp could not be loaded from the timestamp query cache region
void updateTimestampsCachePut()
- This callback is called when the tablespace last update timestamp is added to the timestamp query cache region
Concurrency-control metrics
void optimisticFailure(String entityName)
- This callback is called when an optimistic locking exception is thrown.
These callbacks are very useful if you want to customize the Hibernate Statistics mechanism.
Activating the statistics mechanism
By default, the statistic mechanism is disabled. To enable it, you need to set the following configuration property:
<property name="hibernate.generate_statistics" value="true"/>
Once activated, the metrics are stored in the org.hibernate.stat.internal.StatisticsImpl
object.
To see the statistics printed in the log, you need to set the following logger:
<logger name="org.hibernate.engine.internal.StatisticalLoggingSessionEventListener" level="info"/>
Afterward, Hibernate is going to print the following log entries:
INFO [Alice]: o.h.e.i.StatisticalLoggingSessionEventListener - Session Metrics { 307100 nanoseconds spent acquiring 1 JDBC connections; 55100 nanoseconds spent releasing 1 JDBC connections; 13868600 nanoseconds spent preparing 3 JDBC statements; 3504100 nanoseconds spent executing 3 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; 53460600 nanoseconds spent executing 1 flushes (flushing a total of 3 entities and 2 collections); 0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
Cool, right?
I'm running an online workshop on the 11th of October about High-Performance SQL.If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The statistics mechanism is a very useful way to get a better insight into Hibernate internal workings. While the Statistics
object is used to read the metrics, the StatisticsImplementor
is useful when you want to customize the way the metrics are collected.
