Java Persistence’s TABLE_PER_CLASS Is Evil

TL;DR – TABLE_PER_CLASS inheritance strategy uses some of the most inefficient ways to query. Your database performance will be dragged down as the data grows — consider switching to JOINED.

Slow performance explained

Consider a simple entity hierarchy: ParentClass, ChildClassA and ChildClassB.

public class ParentClass {
public Int id;
  /* excluding extra code for verbosity */
public class ChildClassA { … }
public class ChildClassB { … }

Calling a simple em.find(ParentClass.class, id) would make Hibernate generate the following native query:

(SELECT, … FROM child_a AS _a
WHERE id = ‘…’;

You might have realized there are two fundamental flaws with this query:

  1. All of the table’s data is loaded-absolutely critical to keep in mind, especially when tables have millions of records or when there is a more complex hierarchy at play.
  2. Since the criteria is done on the absolute collective of the tables, all of the indices which the tables have are completely unused. Even worse, the criteria are now working against no indices!

Using JOINED as a solution

One way to go around this is by changing the inheritance strategy to JOINED, which essentially introduces the third, parent table: parent.

Calling em.find(ParentClass.class, id) generates a far more optimized query:

SELECT, ...,, ...,, ...
FROM parent AS _p
INNER JOIN child_a AS _a on
INNER JOIN child_b AS _b on
WHERE '...';

Joining on the table’s own primary keys would link the tables together more optimal, allowing for faster querying.

That’s all I have to say! Do you have another alternative you would like to share, or a justification on when to use TABLE_PER_CLASS? We’d be happy to know in the comments below!

No one likes another outdated article. If you feel it can be improved or keep it up-to-date, I would very much appreciate getting in touch with me over twitter @mcac0006.