The ProblemI was working on a project that used a stored procedure to perform database inserts. This project was in the process of migration from EJB2 Entity Beans to a JPA implementation using Hibernate. This stored procedure was the only one in the whole application and I could not see a need for it. There were several reasons why this stored procedure was not desirable:
- It was database specific. This meant that each developer needed access to an enterprise database in order to run any integration testing. Developers were not able to setup their own databases for integration testing (i.e. HSQLDB or even a local MySQL)
- It contained business validation logic. This meant that the full application logic could not be tested without being connected to the enterprise database. No working on the bus on the way into work, etc. Say hello to VPN connections and every developer needing a copy of the database schema...not a very scalable approach to development
- Dealing with inserts into this particular table with a stored procedure while using Hibernate for everything else muddied up the overall design of the code making it an overly complicated mixed bag instead of a concise abstraction
When I proposed getting rid of the stored proc to simplify the design I was told: "Stored procedures are faster than ORM. Use the stored procedure." When I persisted and asked for further information to support this claim I was told "they just are".
I find this kind of attitude more common than I would hope in the Computer Science discipline. After all, the word "science" is right there in the title. Anyway, with the help of one of my colleagues I put together a test suite to exercise the code using both JPA/Hibernate and stored procedures. The results are summarized below:
ConclusionsBased on this information we can draw a few conclusions:
- The fastest single time was acheived with stored procedures
- The slowest single time was acheived with JPA/Hibernate
- Overall performance was very comparable with a maximum variance of ~150ms
In fact, when the results were averaged, the results were:
- Stored Procedures: 99.98ms
- ORM: 124ms
There are a couple of techniques that could be implemented that would potentially boost the performance of the JPA implementation. One is PreparedStatement caching, the other is the use of a second-level cache such as Ehcache. I will likely re-run the test with these enhancements (in my spare time....ha!) and post my findings.
So the question becomes: is a less than 25ms differential worth the added complexity and maintenance costs of coupling your development to a particular enterprise database platform? Largely it depends on the throughput demands of your application. If this were a trading application with ridiculously high volume and real-time requirements then every single millisecond might be worth the cost. For most of us though, the value of simplified design and portable development outweigh the potential costs many times over.
One added gotcha...One thing we discovered while writing the test suite was that our model is not thread-safe. The model contains a running balance and a per user counter that needs to be incremented for each insert. To further complicate things, this application is clustered so even if we did make the Java objects thread-safe, there is nothing to stop different nodes in the cluster from corrupting each other's data. While this is very unlikely to occur in production, as a responsible developer it's my job to consider and avoid these situations. It turns out that the stored procedure locks the row in the database essentially providing synchronization at the database level (and therefore across the cluster). While this may seem like a benefit, it actually limits throughput as it is pessimistic locking. JPA/Hibernate would be able to perform optimistic locking with the addition of a version column to the table. This however would require changes to another monolithic stored procedure that I recently discovered was also making inserts to the same table. I guess I'm stuck with the stored proc for the forseeable future.
And the award for the longest most rambling blog post goes to...