I spent my Friday doing quite a bit of performance benchmarking, and some of the observations where quite eye-opening.

The basic test was retrieving 50 different objects with 2 related collections per object (1-to-many mapping with Hibernate) 1000 times. I did four different tests:

  • With Hibernate, no caching: test took 192 seconds.
  • With Hibernate, EHCache enabled as 2nd level and query cache: 60 seconds.
  • Direct access to EHCache, only use Hibernate on a cache miss: 20 seconds.
  • Direct access to EHCache, only use Hibernate on cache miss, only open a Hibernate session when required: 1 second.

It has to be noted that my initial results with Hibernate and EHCache as a Hibernate cache was even worse – there are a few gotchas in there, among them being applying the Caching annotations on both class and collection relationship level, and enabling the query cache properly.

But still, the best case is a factor of 60 better than the best case with Hibernate caching, and almost 200 times better than no caching at all!

It’s quite obvious from these numbers that caching can improve performance tremendously, even in the “worst” case with caching.
However there are a few take-aways from this apart from that simple observation – it would seem that Hibernates use of second level and query caching is highly inefficient compared to just hitting a cache explicitly yourself, why this is, I do not know.
Secondly, there seems to be a major overhead in just opening and closing Hibernate Sessions (as per the Open Session in View/transaction per request pattern).

The fact that in-memory operations are quicker than a relational database is hardly a surprise, but even when Hibernate is not supposed to do any queries, it seems to slow things down, which to me is a surprise (indicates to me it’s doing things internally it shouldn’t, or doing things it should very inefficiently).

The Open Session in View pattern is extremely convenient and productive to use for developers – but I think my findings make a pretty good case for someting akin to a “lazy initialized Open Session in View” – where you would have a “transaction context” of sorts around a request-response, but only actually initialize it IF you have cache misses OR need to write to the database.
Spring and Hibernate most certainly do not do anything like this in their implementations of the OSIV pattern, I found they will happily get a db connection for each request regardless of whether it is actually needed or not.

Finally, I should add that the Open Session in View pattern and these findings should not be a problem for 99% of web apps/sites, but at the moment I am working on one of those diverging high traffic, high volume sites where this might become an issue..