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!
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:
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:
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
<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), (AccountTransaction) tuple, longValue(tuple) )) .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
CriteriaQuery and has the following dependencies:
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.
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.