We recently switched our client database implementation from Mckoi to Derby due to some performance issues we’d run into. All was going well, performance was up significantly and everyone was happy, that was until Friday when one of the developers noted that performance had dropped a little then promptly went on holidays :).
It wasn’t until today that I got around to integrating the new database into the client application. Once I did I pulled some customer information from the server onto the client and waited, and waited, and waited, then the sinking feeling came. First I checked to see if I’d done something lame, like turned off the turbo switch (anyone else remember when PCs had turbo switches?), nope, everything pretty much checked out. Bum.
So out comes the trusty profiler, Yourkit, odd name, great profiler. Quick run through with yourkit collecting profiling information and it was apparent that we were compiling statements far more often than we should have been. The code seemed to be doing the correct thing. We use prepared statements almost everywhere, still the database log and yourkit where showing that each time the statement was used it was being recompiled.
Okay time to attach the Derby source and set a couple of breakpoints to get a better idea about what was going on. Nope the Derby source is compiled without debug symbols. That’s okay, it’s open source, I can recompile it myself. Now I’m only going to say one thing about the whole sordid process. Any ant build that has a property named sane that must be set to false to get the build to work has some very serious issues.
Now, finally, after the shock and horror of building Derby, I begin to trace execution. There are some prepared statements, there they are getting cached, all good. Let the application run and enter the area running slowly, what, the cache is empty, huh? I saw statements in there just a moment ago. Trace, click follow, ooohhh. It seems that one of the last little optimisations / sanity checks added by my holidaying colleague before departing, was to drop a constraint before running a series of operations. It was then added back (the database is accessed by a single user on a single thread) once everything was done. Unbeknown to him once you make a DDL manipulation call in a Derby transaction no statements will be cached and every call recalculates the plan. Eeeks, a minor modification to drop and restore the constraints in separate transactions did no end of good.
Derby’s documentation could have been a little clearer. It states that the following must be true for the prepared statement to be cached:
- The text must match exactly
- The current schema must match
- The Unicode flag that the statement was compiled under must match the current connection’s flag
Obviously we were violating the second point. It didn’t occur to me because the manipulation is done once at the start of the operation and the schema is the same for all calls after that. There is no mention of the fact that no statements will be cached until the transaction manipulating the schema commits. At least with the source available I was able to trace through and locate the cause.
Recent Comments