jsonカラムってどうなのよ
MySQLでもPostgreSQLでもjson型をサポートし、
それぞれの方法でindexもはれるようになった。
正直便利な事この上ないが、じゃー使うかーって気軽に使ってしまっていいものだろうか。
Railsのserialize
が遅いのはもはや有名な話だが、
json型での読み書きはどの程度のものなのか、気になったので調べてみた。
結論
先に結果だけ見たい方用に。
結果的には大差無いです。以下計測。
実行環境
- MacBook Air (13-inch, Mid 2013)
- OS: macOS High Sierra 10.13.1
- CPU: Intel Core i7 1.7GHz
- メモリ: 8GB 1600MHz DDR3
- Rails: 5.1.4
- MySQL: 5.7.20
前提
- 全ての比較検証は
rails console
から行っています - 比較実行前にテーブル内は空にしています(db:rollback -> db:migrate)
- indexをはった場合の速度は見ません
- メモリ効率に関しては見ません
環境準備
$ rails g model serialize_sample name:string content:text
$ rails g model json_sample name:string content:json
$ rails db:migrate
app/models/serialize_sample.rb
class SerializeSample < ApplicationRecord
serialize :content, Hash
end
app/models/json_sample.rb
class JsonSample < ApplicationRecord
end
比較1:Insert
require 'open-uri'
require 'benchmark/ips'
Rails.logger.level = Logger::INFO
test_hash = JSON.parse(open("https://gist.githubusercontent.com/gnip/764239/raw/be630cd72a14d0f6033030381dbf45b97ecf3eb7/Twitter%2520(json%2520format).js").read).with_indifferent_access;
Benchmark.ips do |x|
x.report("serialize") { SerializeSample.create(name: 'insert', content: test_hash) }
x.report("json") { JsonSample.create(name: 'insert', content: test_hash) }
x.compare!
end;
結果
Warming up --------------------------------------
serialize 12.000 i/100ms
json 28.000 i/100ms
Calculating -------------------------------------
serialize 129.386 (± 2.3%) i/s - 648.000 in 5.011266s
json 286.639 (± 5.6%) i/s - 1.428k in 5.000155s
Comparison:
json: 286.6 i/s
serialize: 129.4 i/s - 2.22x slower
比較2:Read
require 'open-uri'
require 'benchmark/ips'
Rails.logger.level = Logger::INFO
test_hash = JSON.parse(open("https://gist.githubusercontent.com/gnip/764239/raw/be630cd72a14d0f6033030381dbf45b97ecf3eb7/Twitter%2520(json%2520format).js").read).with_indifferent_access;
100.times do
SerializeSample.create(name: 'insert', content: test_hash)
JsonSample.create(name: 'insert', content: test_hash)
end;
Benchmark.ips do |x|
x.report("serialize") { SerializeSample.find(1).content }
x.report("json") { JsonSample.find(1).content }
x.compare!
end;
結果
Warming up --------------------------------------
serialize 75.000 i/100ms
json 208.000 i/100ms
Calculating -------------------------------------
serialize 760.620 (± 2.5%) i/s - 3.825k in 5.031852s
json 2.077k (± 1.7%) i/s - 10.400k in 5.008244s
Comparison:
json: 2077.2 i/s
serialize: 760.6 i/s - 2.73x slower
追加比較
あれ、SerializeSample
のクラスがHashだからJSONとの比較だと変わるのか・・・と気付き再検証。
serialize :content, JSON
に変更する以外検証内容は変更なし。
app/models/serialize_sample.rb
class SerializeSample < ApplicationRecord
serialize :content, JSON
end
追加比較1:Insert
結果
Warming up --------------------------------------
serialize 28.000 i/100ms
json 27.000 i/100ms
Calculating -------------------------------------
serialize 290.488 (± 4.5%) i/s - 1.456k in 5.023126s
json 282.069 (± 5.7%) i/s - 1.431k in 5.092156s
Comparison:
serialize: 290.5 i/s
json: 282.1 i/s - same-ish: difference falls within error
追加比較2:Read
結果
Warming up --------------------------------------
serialize 217.000 i/100ms
json 201.000 i/100ms
Calculating -------------------------------------
serialize 2.266k (± 1.9%) i/s - 11.501k in 5.076196s
json 2.054k (± 1.8%) i/s - 10.452k in 5.091438s
Comparison:
serialize: 2266.4 i/s
json: 2053.5 i/s - 1.10x slower
総括
散々結果はったものの、結局速度差はたいしてありませんでした、という結果に終わった。
速度比較するまでもなく、コードを見ればやってることは同じなので大差ない事はわかるレベルだったので辛い。
jsonカラムの方が若干処理が多いので、その分速度に出ているのかもしれない。