JPA and First Tier Application Performance Problems
The Performance Zone is presented by AppDynamics. Scalability and better performance are constant concerns for the developer and operations manager. Try AppDynamics' fully-featured performance tool for Java, .NET, PHP, & Node.js.
The performance issue was very important for the customer, so I start investigating this problem first. First things first, I ran the application on client machine and hell it was slow, very slow indeed. It took some 15 seconds for the application to open a JFrame with two auto completing JComboboxs on it. I thought maybe it is the first time I am accessing the database and application is trying to initialize a soft client side cache. So, I closed the JFrame and opened it again. the result was almost the same. I checked network and DNS resolving was fast and no substantial network delay was in place. I thought the problem is either in poor development or something is wrong on database machine.
I asked an operator about the performance and I understand that is a data access problem, and I should focus on that area.
I opened a terminal to the database server machine and checked how much load it is taking when I open that particular JFrame, well there was no substantial load on the server. indeed there was no load on the server. I briefly check to see what kind of indexing we have on two tables where I though are used to load items of the JComboBoxes and hell, no index was created. The developers either were crazy not to have any index except for the default PK index or they had forgotten to execute their post installation script.
I asked for the source code of the application to see what is going on in the application code. The application is based on TopLink Essential which is a part of the GlassFish project, contributed by Oracle for data access. I had some previous experience with Toplink and I was sure that there is nothing wrong with the persistence provider itself.
Application source code was documented but not enough to understand the code easily. I located that JFrame form and checked how they are loading the content of JComboBoxes. Well, they were calling an static method from a DAO class which returns a list an Object named A. Then it was iterating over the list and loading the JComboBox with A.property1. I thought why on earth were they are fetching the entire object to use on property?
I checked the second JC and I found the same steps, a DAO method was called which returns a list and then the JC was loaded using D.property1.
I start looking at these two entities to see what is going on with them and I find that each of them has a one to many relation with at least one other entities. So we basically had something like:
There were no FetchType determined for the relationships so, Toplink assume FetchType.EAGER for the relationships by default. The FetchType.EAGER means that JPA eagerly loads all related records from database and create all corresponding objects before we even start using them.
What does that means? It Means that for the first JComboBox that client application creates num(A)+num(B)+num(C)+num(A)*num(B)*num(C) objects just to show a list of names in a JComboBox. Very funny huh?
I created a development database setup in the development environment (NetBeans works well with ANT based projects) and start changing the code. I didn't change the fetch types, instead I changed the JPA queries to ensure that I am only loading one field and not all fields which have eager fetching relationships. I compiled and the problem for this particular form were solved. I added two indexes to ensure that I am getting the result as fast as possible.
I was thinking about JPA caching and why JPA was not able to improve the overall performance after I closed the form and re-opened it. I think the data load was more than what JPA could cache by default.
I will blog more about these application and its problems. I believe it was either a prototype of the developers were intended to reiterate over the code to improve the performance.