Молниеносный JSON в Ruby on Rails

в 13:47, , рубрики: activerecord, json, oj, ROR, ruby, ruby on rails, yajl

Вывод результата в JSON достаточно прост в Rails:

render json: @statuses

Это работает отлично, если нужно вывести небольшое количество записей. Но что случится, если нам потребуется вывести сразу 10'000 записей? Производительность серьезно просядет, а самыми затратными по времени окажутся сериализация JSON и операции с базой данных.

Молниеносный JSON в Ruby on Rails

Включайте только необходимые атрибуты

Первое очевидное решение — генерировать JSON только с необходимыми нам атрибутами, т.е.:

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

Отфильтрованный JSON даст нам более 20% прироста производительности:

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

Делайте выборку только необходимых полей

Второе решение — забирать из базы не все, а только необходимые нам поля.

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

Это поможет нам избежать передачи огромного количества лишних данных из базы в приложение и даст нам 2х прирост скорости:

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)

Не инициализируйте объекты ActiveRecord, если это возможно

Давайте реализуем метод, который будет возвращать «молниеносный» массив хэшей вместо объектов ActiveRecord:

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

Это работает также как метод pluck, но возвращает массив хэшей, а не массив значений одного поля. Вызовем наш новый метод в контроллере:

render json: @statuses.lightning

Использование легковесных хэшей ускоряет создание JSON еще в 2 раза:

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

На текущий момент доступно несколько библиотек JSON:

  • JSON — gem JSON по-умолчанию (+ C-расширения, поставляется вместе с Ruby 1.9)
  • Yajl — Yet Another JSON Library (автор Brian Lopez)
  • Oj — Optimized JSON (автор Peter Ohler)

Хорошая идея использовать самую быструю из них:

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)

Так что мы выбираем Oj дампер:

render json: Oj.dump(@statuses.lightning, mode: :compat)

Обобщенные результаты теста:

   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)

Автор: Svyatov

Поделиться

* - обязательные к заполнению поля