Hibernate SQM – Semantic Query Model

Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?

What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?

Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?

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

So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!

Introduction

In this article, I’m going to explain what is the Hibernate SQM or Semantic Query Model so that you have a better picture of how JPQL or Criteria API queries are executed by Hibernate.

Hibernate 5, 4, and 3

Prior to Hibernate 6, entity queries were executed as follows:

Hibernate 5 before SQL

Criteria API would simply generate a JPQL, which Hibernate parsed according to its HQL grammar in order to generate the underlying database-specific SQL query.

Having the Criteria API generate JPQL, only to be later parsed, it’s not very efficient, so a better model was designed to handle these entity queries.

Hibernate 6 SQL – Semantic Query Model

Starting with Hibernate 6, this is how entity queries are generated:

Hibernate SQM – Semantic Query Model

JPQL is compiled to SQM while the Criteria API created the SQM nodes right away, therefore improving its efficiency.

To see how the SQM is built, you will have to set the org.hibernate.orm.query.sqm.ast logger to the debug level:

<logger name="org.hibernate.orm.query.sqm.ast" level="debug"/>

And, when executing the following JPQL Window Functions query:

List<StatementRecord> records = entityManager.createQuery("""
    SELECT
       ROW_NUMBER() OVER(       
           PARTITION BY at.account.id
           ORDER BY at.createdOn   
       ) AS nr,
       at,
       SUM(at.amount) OVER(       
           PARTITION BY at.account.id
           ORDER BY at.createdOn   
       ) AS balance
    FROM AccountTransaction at
    ORDER BY at.id
    """, StatementRecord.class)
.unwrap(Query.class)
.setTupleTransformer((Object[] tuple, String[] aliases) -> new StatementRecord(
    longValue(tuple[0]),
    (AccountTransaction) tuple[1],
    longValue(tuple[2])
))
.getResultList();

Hibernate is going to log the following Semantic Query Model Tree:

o.h.o.q.s.ast - SqmStatement Tree :
-> [select]
  -> [query-spec]
    -> [select]
      -> [selection(nr)]
      <- [selection(nr)]
      -> [selection]
        -> [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
        <- [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
      <- [selection]
      -> [selection(balance)]
      <- [selection(balance)]
    <- [select]
    -> [from]
      -> [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
      <- [root] - `com.vladmihalcea.book.hpjp.hibernate.query.window.AccountTransaction(at)`
    <- [from]
  <- [query-spec]
<- [select]

The Hibernate 6 SqmSelectStatement class implements the Jakarta Persistence TypedQuery and CriteriaQuery and has the following dependencies:

SQM Select Statement

By unifying the query model, the Hibernate 6 Criteria queries will be able to be extended with features that are not supported by a given Jakarta Persistence specification, just like the Hibernate HQL provides more features than the standard JPQL specification.

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

Conclusion

Hibernate 6 provides a lot of new features, and the new SQM (Semantic Query Model) is a very powerful API that’s the foundation of many new query functionalities.

With the Hibernate SQM API in place, Hibernate can provide advanced query capabilities that have been previously provided by Blaze Persistence, like LATERAL JOINs, CTE (Common Table Expressions), or Window Functions.

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.