ActiveRecordのserializeでMessagePackを使う

せっかくなのでデフォルト(YAML)、Oj(json)、MessagePackでベンチマークも取ってみました。
保存するデータは http://json-generator.appspot.com/ ここで適当に作ったものをロードして突っ込んでます。
DBに保存していたりしますが、単純にそれぞれのdumpとloadの差です。

```rb:migration
create_table :articles, force: true do |t|
  t.column :body, "MEDIUMTEXT", null: false
  t.timestamps null: false
end

create_table :oj_articles, force: true do |t|
  t.column :body, "MEDIUMTEXT", null: false
  t.timestamps null: false
end

create_table :msgpack_articles, force: true do |t|
  t.column :body, "MEDIUMBLOB", null: false
  t.timestamps null: false
  end
```
MessagePackはバイナリデータなので、BLOB型にしています。


```rb:models
class SerializationOj
  def self.dump(obj)
    Oj.dump(obj, mode: :compat)
  end

  def self.load(json)
    Oj.load(json, mode: :compat) unless json.nil?
  end
end

class SerializationMessagePack
  def self.dump(obj)
    MessagePack.pack(obj)
  end

  def self.load(binary)
    MessagePack.unpack(binary) unless binary.nil?
  end
end

class Article < ActiveRecord::Base
  serialize :body
end

class OjArticle < ActiveRecord::Base
  serialize :body, SerializationOj
end

class MsgpackArticle < ActiveRecord::Base
  serialize :body, SerializationMessagePack
end
```
MessagePackのシリアライズクラスを作ってserializeの第2引数に指定

```rb:benchmark
BENCH_TIMES = 10000
BODY_DATA   = Oj.load(File.read(File.expand_path("../dummy.json", __FILE__)), mode: :compat)

p "file size: #{BODY_DATA.size}"

Benchmark.bmbm do |bm|
  p "yaml"
  bm.report "create" do
    BENCH_TIMES.times do
      Article.create!(body: BODY_DATA)
    end
  end

  bm.report "find" do
    BENCH_TIMES.times do
      Article.limit(100).collect(&:body)
    end
  end
end

Benchmark.bmbm do |bm|
  p "oj"
  bm.report "create" do
    BENCH_TIMES.times do
      OjArticle.create!(body: BODY_DATA)
    end
  end

  bm.report "find" do
    BENCH_TIMES.times do
      OjArticle.limit(100).collect(&:body)
    end
  end
end

Benchmark.bmbm do |bm|
  p "msgpack"
  bm.report "create" do
    BENCH_TIMES.times do
      MsgpackArticle.create!(body: BODY_DATA)
    end
  end

  bm.report "find" do
    BENCH_TIMES.times do
      MsgpackArticle.limit(100).collect(&:body)
    end
  end
end
```

```bash:result
"file size: 87505"

"yaml"
Rehearsal ------------------------------------------
create 194.760000   4.410000 199.170000 (226.059458)
find   1443.380000 145.550000 1588.930000 (1691.537545)
------------------------------ total: 1788.100000sec

             user     system      total        real
create 194.280000   4.370000 198.650000 (249.059130)
find   1443.510000 145.030000 1588.540000 (1690.263404)


"oj"
Rehearsal ------------------------------------------
create  50.360000   3.440000  53.800000 ( 83.307643)
find   392.770000 137.870000 530.640000 (633.403793)
------------------------------- total: 584.440000sec

             user     system      total        real
create  50.550000   3.320000  53.870000 (116.603378)
find   393.820000 138.790000 532.610000 (635.451361)


"msgpack"
Rehearsal ------------------------------------------
create  13.390000   3.490000  16.880000 ( 39.246475)
find    75.450000 103.490000 178.940000 (268.235375)
------------------------------- total: 195.820000sec

             user     system      total        real
create  15.200000   3.670000  18.870000 (147.845164)
find    75.580000 104.860000 180.440000 (269.350645)
```

MsagePack速い！ :stuck_out_tongue_closed_eyes: