views:

250

answers:

11

I'm doing a school software project with my class mates in Java. We store the info on a remote db.

When we start the application we pull all the information from the database and transform it into objects to use in our application (using java sql statemens). In the application we edit some of these objects and then when we exit the application we save or update information in the database using Hibernate.

As you see we dont use Hibernate for pulling in information, we use it just for saving and updating.

We have 2, but very similar problems. The loading of object(when we start the app) and the saving of objects(with Hibernate) in the db(when closing the app) is taking too much time. And our project its not a huge enterprise application, its a quite small app, we just manage some students, teachers, homeworks and tests. So our db is also very very small. How could we increase performance ?

later edit: if we use a local database it runs very quick, it just runs slow on remote databases

+6  A: 

Are you saying you are loading the entire database into memory and then manipulating it? If that is the case, why don't you instead simply use the database as a storage device, and do lookups and manipulation as necessary (using Hibernate if you like, or something else if you don't)? The key there is to make sure that you are using connection pooling, as that will reduce the connection time.

If this is what you are doing, then you could be running into memory issues as well - first, by not caching the entire database in memory, you will reduce memory and will spread out the network load from the beginning/end to the times when it needs to happen.

aperkins
Based on your edit, I would guess it is, in part, because of the transfer times between the machine and the remote database - i.e. the transfer of all that data at startup/shutdown.
aperkins
+2  A: 

For what you are doing, you may very well be better off serializing your objects and writing them out to a flat file.

But, much more likely, you should just read / update objects directly from your database as needed instead of all at once, for all the reasons aperkins gives.

Also, consider what happens if your application crashes? If all of your updates are saved only in memory until the application is closed, everything would be lost if the app closes unexpectedly.

Chris Lawlor
A: 

The project its pretty much complete. we cant do large refactoring on it now. I tried to use a second level cache for Hibernate when saving. EhCacheProvider.

in hibernate.xml: net.sf.ehcache.hibernate.EhCacheProvider

i have done a config for the cache, ehcache.xml:

i have put the cache.jar in the project build path and i have set the hibernate property for every class and set in the mapping. But this cache doesn't seem to have an effect. I dont know if it works(if it is used).

Blitzkr1eg
Ehcache isn't going to help you if you're not loading the database objects using Hibernate. It will only cache entities loaded through Hibernate and prevent you from round-tripping to the db if you request the same entity again. BTW, here's some code for printing out ehcache stastics for 1 ehcache.xml entry:import org.hibernate.SessionFactory;import org.hibernate.stat.SecondLevelCacheStatistics;SecondLevelCacheStatistics settingsStatistics = sessionFactory .getStatistics().getSecondLevelCacheStatistics( fullyQualEntityImplName);
elduff
A: 
  1. Try minimising number of SQL queries, since every query has its own overhead.
  2. You can enable database compression, which should speed things up when there is a lot of data.
  3. Maybe you are connecting to the database many times?
  4. Check the ping time of remote database server - it might be the problem.
marpetr
+4  A: 

These 2 sentences are red flags for me :

When we start the application we pull all the information from the database and transform it into objects to use in our application (using java sql statemens). In the application we edit some of these objects and then when we exit the application we save or update information in the database using Hibernate.

Is there a requirements reason that you are loading all the information from the database into memory at startup, or why you're waiting until shutdown to save changes back in the database?

If not, I'd suggest a design change. If you've already got Hibernate mappings for the tables in the DB, I'd use Hibernate for both all of your CRUD (create, read, update, delete) operations. And, I'd only load the data that each page in your app needs, as it needs it.

If you can't make that kind of design change at this point, I think you've got to look closely at how you're managing the database connections. Are you using connection pools? Are you opening up multiple connections? Forgetting to release them?

Something else to look at. How are you using Hibernate to save the entities to the db? Are you doing a getHibernateTemplate().get on each one and then doing an entity.save or entity.update on each one? If so, that means you are also causing Hibernate to run a select query for each database object before it does a save or update. So, essentially, you'd be loading each database object twice (once at the beginning of the program, once before saving). To see if that's what's happening, you can turn on the show_sql property or use P6Spy to see exactly what queries Hibernate is running.

elduff
If I was their instructor, they would flunk for using such a poor architecture.
HLGEM
@HLGEM: That is the whole point of taking a class however - is to learn about these types of problems before entering industry. I would much rather have people run into them in school, than in the "real world" - having seen too many examples of this exact behavior in the "real world"
aperkins
Well, yes and if it was my project it wouldn't have gotten to this, but some class mates found hibernate cumbersome, and thats why we dont have lazy fetching, witch would solve one problem.
Blitzkr1eg
Yeah, this kind of thing is tricky when you're working in a group.
elduff
@Blitzkr1eg - This problem doesn't necessarily change in the real world either. I still have to explain to people why proven X, Y, or Z technology is a Good Thing(tm). (Source control is one of these things...gah!)
JasCav
@elduff `Yes` at your last (4th) paragraph. It there a way in which hibernate doesn't need to do SELECT statements when saving ?I know only one scenario, when the JAVA Object gets edited in the same session. But in my case, that Object need to leave the session to enter the GUI, where it gets edited and then back to another session and saved.
Blitzkr1eg
A: 

As your application is just slow when running on a remote database server, I'd assume that the performance loss is due to:

For hibernate you may use its batch functionality and adjust hibernate.batch_size.

In all cases, especially when you can't refactor larger parts of the codebase, use a profiler (method time or sql queries) to find the bottleneck. I bet you'll find thousands of queries, each taking 10ms RTT) which could be merged into one.

Wikser
When we start the app, we open one single connection. Execute all queries and the close the connection.
Blitzkr1eg
A: 

Some other things you can look into:

  • You can allocate more memory to the JVM
  • Use the jconsole tool to investigate what the bottlenecks are.
James Kingsbery
+2  A: 

The difference in loading everything from a remote DB server versus loading everything from a local DB server is the network latency / pipe size. The network is a much smaller pipe than anything else. Two questions: first, how much data are we really talking about? Second, what is your network speed? 10/100/1000? Figure between 10 and 20% of your pipe size is going to be overhead due to everything from networking protocols to the actual queries themselves.

As others have stated, the way you've architected is usually high on the list of "don't do". When starting, pull only enough data to initialize the app. As the user works through it, pull what you need for that task.

The ONLY time you pull everything is when they are working in a disconnected state. In that case, you still don't load everything as objects in the application, you just work from a local data store which gets sync'ed with the remote server every so often.

Chris Lively
to answer your questions:1. the db is small, ~120 KB. thats KilloBytes2. the server has a speed of 100 Mbits, thats like 12MBytesSo the problem is not here.
Blitzkr1eg
@Blitzkr1eg: Just because it has a 100Mb NIC, doesn't mean it's actually transferring at that rate. Depending on a lot of other factors (network health, drivers, etc) it could be transferring at only 1Mb/sec.
Chris Lively
A: 

Why dont you have two separate threads?

Thread 1 will load your objects one by one. Thread 2 will process objects as they are loaded.

Your app will seem more interactive at startup.

Ram Bhat
Yes, that is the solution i have thought of. Now i just cant implement it.
Blitzkr1eg
Why cant u implement it? Creating threads isn't actually that big a refactoring process as u think it is ESPECIALLY in java, Just make sure you have no problems with sync
Ram Bhat
I did it with threads, at least for the save. Its far from being a good solution but its a little bit more responsive.
Blitzkr1eg
A: 

It never hurts to review the basics:

Improving speed means reducing time (obviously), and to do that, you find activities that take significant time but can be eliminated or replaced with something that uses less time. What I mean by activity is almost always a function call, method call, or property call, performed on a specific line of code for a specific purpose. If may invoke I/O or it may invoke computation, or both. If its purpose is not essential, then it can be optimized.

Many people use profilers to try to find these time-wasting lines of code, but most profilers miss the target because they look at functions, not lines, they go to sleep during I/O, and they worry about "self time".

Many more people try to guess what could be the problem, or they ask others to guess, such as by asking on SO. Such guesses, in the nature of guesses, are sometimes right - more often not, but people still invest time and resources in them.

There's a very simple way to find out for sure, without guessing, what could fruitfully be optimized, and here is one way to do it in Java.

Mike Dunlavey
A: 

Thanks for your answers. Their were more than helpful. We completely solved this problem like so:

Refactored the LOAD code. Now it uses Hibernate with Lazy Fetching. Refactored the SAVE code. Now it saves, just the data that was modified and right after the time it was modified. This way we dont have a HUGE save an the end.

Im amazed of how good it all went. The amount of new code we had to write was very very small.

Blitzkr1eg