Fast Rails API

Fast Rails API

Rendering JSON is pretty easy in Rails.

1
render json: @statuses

It works well if there are small number of records to be returned. But what happens when we need to return 10,000 records at once? Things slow down dramatically and the most time-consuming parts are JSON serialization and database operations.

Include only Required Attributes
The first obvious thing is generating JSON with only attributes that we need.

1
render json: @statuses, methods: [:latitude, :longitude, :timestamp, :virtual_odometer]

Tidying JSON gives over 20% performance

1
2
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)

Select only Required Columns
Second, we should consider selecting only required columns when we don’t need all of them.

1
render json: @statuses.select([:latitude, :longitude, :timestamp, :virtual_odometer])

It’ll help us to avoid transferring a huge amount of data to the application from the database and gives 2x speed up.

1
2
3
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)

Don’t Instantiate ActiveRecord Objects If Possible
Let’s implement a method to return “lightning” array of hashes instead of ActiveRecord instances.

1
2
3
4
5
6
7
def self.lightning
  connection.select_all(select([:latitude, :longitude, :timestamp, :virtual_odometer]).arel).each do |attrs|
    attrs.each_key do |attr|
      attrs[attr] = type_cast_attribute(attr, attrs)
    end
  end
end

Returns array of hashes instead of array of single column values. Invoke a new method in controller.

1
render json: @statuses.lightning

Using lightweight hashes makes JSON rendering 2x faster.

1
2
3
4
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)
lightning  1.120000   0.010000   1.130000 (  1.148763)

Fastest JSON

There are several JSON libraries available:
- JSON - The default JSON gem with C-extensions (ships with Ruby 1.9).
- YAJL - Yet Another JSON Library.
- OJ - Optimized JSON.

It’s a good idea to use the fastest dumper of them.

1
2
3
json       0.810000   0.020000   0.830000 (  0.841307)
yajl       0.760000   0.020000   0.780000 (  0.809903)
oj         0.640000   0.010000   0.650000 (  0.666230)

But we prefer active_model_serializers which it run faster than OJ.

Summarized benchmark results are:

1
2
3
4
5
6
7
8
9
user     system      total        real
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)
lightning  1.120000   0.010000   1.130000 (  1.148763)
json       0.810000   0.020000   0.830000 (  0.841307)
yajl       0.760000   0.020000   0.780000 (  0.809903)
oj         0.640000   0.010000   0.650000 (  0.666230)
ams        0.270000   0.000000   0.270000 (  0.272239)

So far so good, That’s it!!! See ya!!! :)