[2018 oracle code one] mastering jpa performance

Mastering JPA Performance
Speaker: Thomas Broll
@speakjava

For more blog posts, see The Oracle Code One table of contents


Problem

  • Users complain
  • With microservices more important beause more calls

General

  • Apache lang has ImmutableTriple class

Techniques

  • Monior – number sql statemtenrs, cpu, i/o
  • hibernate.show_sql = true
  • run jstack while transaction running to see where stuck
  • Check JDBC driver batch size

Create – Performance improvements

Scenario: writing large amounts of data

  • Use table generator (vs sequence generator) where gt batch of ids so not a roud trip to get it each time. Even better to use external UUID generator
  • JPA only supports one open batch. But goes to database if do a query or persist a different entity. So faster if persist by entity

Read – Performance improvements

  • 1+N problem. One statement in code. Executes more statement to get relationships. All, XToOne are eagerly loaded
  • Can provide hints to eagerly or lazy load
  • fetch query to get data actually needed – can put it in the JQL query
  • Can get Hibernate statistics for number of queries/loads/fetches
  • Cal setFirstResult() and setMaxResults() on query object

Update – Performance improvements

  • Auto flushes are caused by transaction commit, insert/delete, query or explicitly flush()
  • Performance cost due to dirty checks and actual updates. Cost also depends on size of persistence context
  • Call getReference() to get empty proxy. This allows saving without changing in database?

Delete – Performance improvements

  • Remove() requires persistent entities, requires loading reference
  • Delete by query could be more efficient

Cloud

  • Two orders of maginude worse when database on different continent.
  • 35 minutes to do 5 second run when database on a different continent

My take: It’s been a while since I look at this topic. It was a good mix of review and things I never knew. Not having a physical network between the machine and database really hanges the numbers. It would have been nice to use a cloud database to get those numbers [scratch that; he did at the very end. I would have liked to see it earlier]

Hibernate anti-patterns and best practices – the server side java symposium

I was disappointed with this speaker’s previous session so I wasn’t sure whether to attend this one. I did like parts of this session better. It was interactive and presented alternate options. There was also a SQL/hsql puzzle to practice spotting errors. Similarly for java.

Transactional issues
Race condition if don’t have right transaction settings. Could solve with proper isolation level of serializable, but slows performance a lot. Repeatable read would not be ok because new row created in this example that not included in max so range query. Hibernate versioning also doesn’t help because on different table. Recommends reordering code so get Lock.UPGRADE first Note this is not a hibernate specific problem. The solution sounds like “for update” mode in Oracle. The speaker also noted an object should not be passing around internal state. Also not Hibernate specific, a query should be done in one step where possible.

other approaches:

  • track everything in Java, but then lose benefit of database
  • denormalize database
  • Use custom mappings with custom queries, laziness and order or where clause

Object oriented issues
Returning the raw list lets callers modify it, encapsulation matters, do not want inconsistent object state

To avoid

  • Write business methods before accessors
  • Hibernate can work with private, protected and package access
  • Date and Collections are the most likely causes of mutable internal state. Note that defensive copying requires retrieving all objects from thedatabase. Also Collections.unmodifiableList() is a problem because the dirty read check looks at the identity of objects.

Performance issues
There was some reuse in this section from the presenter’s other breakout.
Hibernate can be slow depending on usage. Having a getter return an unmodifiable list when cascade all is on, Hibernate deletes the whole collection and recreates if. The reason is that Hibernate sees the list as having a different identity. Thus can happen when calling get under certain conditions.

Automated detection
We got to hear content from the static analysis talk again. I didn’t like it any better this time because it is still vague.

Other things one could do wrong
Remember where clause criteria
Remember order of args in compareTo()

Conclusion – hibernate is hard, there will be a solution to make it easier one day