Monday, December 08, 2008

Replacing ActiveRecord with DataMapper in Ruby on Rails

This is for the technically minded as it deals with replacing ORMs in a Ruby on Rails application.

I recently had an opportunity to do a little presentation and I chose to talk about replacing the ActiveRecord ORM (Object Relational Mapper) with DataMapper in a Ruby on Rails application. DataMapper was incredibly fast at returning records. For a single table look up, it took 0.0150% of the time that ActiveRecord took to return all 10,000 records. Holy Toledo!

Here, check this out. This is a series of benchmark runs between two nearly identical applications. They both have the exact structure, number of pages, etc. and same number of pages. But, one application is using ActiveRecord and the other is using DataMapper.

10,000 Records recalled with ActiveRecord

#1 1.050000 0.040000 1.090000 ( 1.227590)
#1 1.050000 0.020000 1.070000 ( 1.222924)
#1 1.080000 0.020000 1.100000 ( 1.250905)
#1 1.100000 0.030000 1.130000 ( 1.288719)
#1 0.860000 0.020000 0.880000 ( 1.724392)

Average: 1.342906

10,000 Records recalled with DataMapper

#1 0.000000 0.000000 0.000000 ( 0.000198)
#1 0.000000 0.000000 0.000000 ( 0.000196)
#1 0.000000 0.000000 0.000000 ( 0.000204)
#1 0.000000 0.000000 0.000000 ( 0.000205)
#1 0.000000 0.000000 0.000000 ( 0.000202)

Average: 0.000201

Datamapper requires 0.0150% as much time as ActiveRecord

One cool thing about doing this presentation is that when I started encountering problems with working on Rails in XP (although I know it is possible for the most part), I decided to create a Linux installation. My first thought was to repartion my hard drive and install Linux there. But, I'm using an older machine and was afraid of data loss (fortunately, I use an online backup solution for recoverability, but there is still all that work to do). Therefore, I ended up creating a persistable Ubuntu 8.10 installation on a 2 GB Flash Drive. That will have to be a topic for another post.

The presentation is available on SlideShare for your viewing pleasure. I walk through the steps in the presentation after a very quick overview of ActiveRecord and DataMapper. The source is available on github.

Please use the SlideShare posting and the github source for your resources. I used the DataMapper web site, of course, as a primary reference. I also used
Fran├žois Beausoleil's blog, How to Use DataMapper From Rails, Including Migrations and Tests, to get started.


  1. There's something about those numbers that appears a bit fishy. Currently there are some things DM is faster at than AR, and some things that AR is faster at (but we're closing the gap, we haven't really done any serious optimizing yet). If you see anything more than a 2-3x gap I would question it, because there's only so fast the underlying database can execute the queries.

  2. @dkubb; I'll grant that the test was very straight forward and did not contain sufficient real-world data complexity to provide a performance test bed upon which I would rest a recommendation. The assumption is that DM would be generally faster than AR and the purpose was to figure out how to swap out one for the other.

    The basis for the assumption is the significantly lower overhead DM has compared to AR. For example, in retrieving 1,000 records, AR made some 204,000 calls (profiling code included), where as DM made less than 7,000 calls.

    I hope to have some more real world appropriate examples as the opportunities arise. So, I don't at all dispute your position and simply point out the results may be a factor of simplicity of the test.

  3. @peter: oh I'm not complaining. :) I love to see people test out DataMapper and blog about their results.

    BTW: It appears that your tests do not use the Identity Map at all. With it you should see even further improvements in Model#get calls. To use it, make an around filter, and have a repository block wrap the yield. What it will do is cache the first lookup on each request, and subsequent lookups will pull from the Identity Map instead of the storage engine.

    We probably should bake this into the rails_datamapper plugin so it becomes common-place when using DM inside Rails.