1

I maintain a website of events taking place in my city.

My website homepage is a 5-days calendar with all the events taking place from today to 4 days in the future.

I have done quite a good job with my "ActiveRecord" code as I have around ~120ms spent in MySQL (double checked with RackMiniProfiler) to load ~200-300 events.

However my response time is very slow (1.5s - 2s).

Most time is spent in instantiation of AR's objects from my queries

Using ObjectSpace, I see that ~6k AR::Base objects are instantiated for +300 events that are displayed.

The reason why there are so many objects is that my Event model has many associated models (e.g. venue, occurrences, categories, etc...), all of which contain bits of information I need to show.

As expected, profiling proved ActiveRecord's object instantiation as the most consuming task during the request.

I am not experienced enough in neither ActiveRecord nor its performance.

Is such speed expected or should my objects be instantiated much faster?

Should I move away from AR and use simple ruby hashes?

Is this the Rails standard when my data model is too complex?

========= UPDATE 1 =========

This pastebin contains the service class I use to load the events for a single day in the calendar. I hope it's understandable, I did not have time to properly document it since it's still a work in progress to improve performance.

========= UPDATE 2 =========

Loading all these objects has another drawback: it causes GC runs while the page is being rendered, adding ~100ms after every n events are rendered, which becomes a total overhead of ~500ms.

To give you an idea of how much data I'm loading (sadly 99% of it is needed), if I dump to JSON I get a 47K file.

========= UPDATE 3 =========

As mentioned by @TheSuper, even though it does not improve AR's performance, fragment caching is indeed my friend as I'm rendering quite the amount of data while under GC runs. Applying fragment caching yielded a 1-1.2s improvement, which is HUGE.

However I still cannot overcome the 600ms wall of AR. A possible improvement are "selective includes" discussed in this answer, for the few cases where I need a small portion of the attributes of an included model, but this is ugly and inflexible.

Community
  • 1
  • 1
Cec
  • 1,726
  • 3
  • 18
  • 31
  • 1
    Caching is your friend here. Rails has some excellent guides on how to do it, and you'll see huge speedups. – TheSuper Jun 10 '15 at 16:53
  • 1
    some code would help. – neo Jun 10 '15 at 16:57
  • @TheSuper thx for the quick reply. If I am not wrong, russian doll caching needs the AR object to have a timestamp for generating the cache-key, therefore wouldn't all the objects be instantiated anyway? – Cec Jun 10 '15 at 17:08
  • @neo I updated my answer. I believe the code to be too messy at the moment. In my place it 7PM, tomorrow I'll better document the class and update the pastebin – Cec Jun 10 '15 at 17:10
  • A quick test of one of my smaller models instantiates 6k of them in around .25 seconds. – ABMagil Jun 10 '15 at 17:23
  • @ABMagil your timings are very compatible with mine: a simple model takes 250ms and a more complex model (if I convert to json I get a 47K document) takes ~600-800ms – Cec Jun 10 '15 at 21:55
  • Garbage Collection has undergone quite a bit of change in the last few versions of ruby. Which version are you using? – ABMagil Jun 11 '15 at 13:57
  • Also, how could you possibly need all that data _at once_? Is it possible to significantly increase the ajaxiness of your app and reduce the initial payload? – ABMagil Jun 11 '15 at 14:06
  • @ABMagil I have thought about that for quite some time, but because of some problems specific to calendars I did not find a way. I would love to discuss this with you, but I believe that another medium should be used as it would be off-topic for this question. – Cec Jun 11 '15 at 15:30

0 Answers0