Mr eel
Hibernate vs. Rails
It’s been awhile since I’ve written anything about Ruby on Rails, but this one article that caught my eye. Hibernate vs. Rails: The persistence showdown. It’s a comparison of mainly the object relational mapping layer of Rails (ActiveRecord) against Hibernate. It’s fairly even-handed and the critisims of Rails are generally valid.
For example Patrick rightly points out that in general Rails is more suited to green field (brand spanking new, without legacy DBs) web apps. This of course is intentional, but needs to be considered when choosing a framework. Simply, Rails might not be suited to you.
I think this article might have been written with an older version of Rails, or Patrick isn’t that familiar with the framework. That old bug-bear scaling crops up again. It’s worth pointing out that despite what the article says, you can tune your database queries and can do so without needing to write hideously long SQL queries (for most cases, see below). For example, eager cascading loads will load a set of objects, and the specified associated objects in one SQL query.
@records = Record.find(:all, :include => :tracks)
The :include bit is the important part there. Queries can also get more complicated by specifying the inclusion of more associations, and then their associated objects. This goes a long way to improving performance. I’ve begun using it extensively and it’s brilliant.
Patrick also makes a good point about lazy loading. This is where the ORM loads all of the fields for a object, regardless if you need them or not. This is the simplest solution. You never need to think about what fields your object currently has loaded, you can simply make the assumption that they’re all there for you to use.
But in some situations you may find it’s a drain on resources. Imagine a situation where you load 1000 records, but only need to access the ‘name’ field. Lazy loading has included a whole bunch of fields we don’t need.
Now we can get past this fairly easily in Rails, with one rather big caveat that I’ll get to in a bit.
@records = Record.find_by_sql(SELECT name FROM records)
Basically we write our own SQL query so that it only grabs the ‘name’ field. The big downside to this is if you wanted to use it with eager loading. There is no way to specify :include with the find_by_sql method. The only option is to have your SQL query join another table and include the fields you want.
For a single field from another table, it’s fairly simple, but once it gets more complicated, it gets much more scary!
There would be some cases where you want to tune your queries within an inch of existence. Hopefully in the future ActiveRecord will expand to allow even more optimisation. We’ll slay that scaling-beast one day!
Comments
Trix on May 7, 2006
Mr eel,
Re. the last query, I’d strongly recommend you don’t do Record.find_by_sql() since you’re not looking for Records to be returned, but just record names.
I do that type of stuff once in a while, and I usually use something like :
@product_names = ActiveRecord::Base.connection.select_values(’SELECT name FROM records’)
It makes it much clearer that you’ve decided to take matters into your own hands, and will probably make your code easier to maintain in the long run.
Mr eel on May 7, 2006
Great suggestion! As you say, no need to turn the Records into actual AR instances, since we only want the names. If we’re collecting 1000’s of records avoiding all those object instantiations will help performance.
Thanks! Gonna put that one in my toolkit
adrian on August 21, 2006
FYI: You have your lazy and eager definitions backwards. lazy = on demand, eager = fetch now.