Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java Persistence’s TABLE_PER_CLASS Is Evil

DZone's Guide to

Java Persistence’s TABLE_PER_CLASS Is Evil

If you use the TABLE_PER_CLASS inheritance strategy, your database performance will be dragged down as the data grows. Switching to JOINED is a good idea.

· Database Zone ·
Free Resource

MariaDB TX, proven in production and driven by the community, is a complete database solution for any and every enterprise — a modern database for modern applications.

The 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.

@Entity
@InheritanceStrategy(TABLE_PER_CLASS)
public class ParentClass {
  @Id
  public Int id;
  /* excluding extra code for verbosity */
}

@Entity
@Table(“child_a”)
public class ChildClassA { … }

@Entity
@Table(“child_b”)
public class ChildClassB { … }

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

(SELECT _a.id, … FROM child_a AS _a 
 UNION 
 SELECT _b.id, … FROM AS _b) 
 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 _p.id, ...,        _a.id, ...,        _b.id, ...   
  FROM parent AS _p   
  INNER JOIN child_a AS _a on _p.id=_a.id   
  INNER JOIN child_b AS _b on _p.id=_b.id 
  WHERE _p.id= '...';

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!

MariaDB AX is an open source database for modern analytics: distributed, columnar and easy to use.

Topics:
performance ,database performance ,joined

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}