Hibernate SQM – Semantic Query Model

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, 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

One Comment on “Hibernate SQM – Semantic Query Model

Leave a Reply

Your email address will not be published.

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