知りたいこと
- 処理中に何回も読みにいくレコードが大量にあって、それを先にメモリに載せて置いたらどのくらい早くなるだろう
- つまり、
Ecto.Repo.get()
と:ets.lookup()
の差 - とりあえずid走査でどうなるかやってみる
- DBは最適化というほど頑張っていない
以下、リソースをUserとしたときの疑似コード
共通処理
- 先に全レコードを読んでレコードを読んでidをシャッフルしておく
users = Repo.all(User)
ids = Enum.map(users, & &1.id) |> Enum.shuffle()
Ecto
ids
|> Flow.from_enumerable()
|> Flow.map(& Repo.get(User, &1))
|> Enum.to_list()
:ets
table = :ets.new(:lookup, [:set, :public])
users
|> Enum.each(fn user ->
:ets.insert_new(table, {user.id, user})
end)
ids
|> Flow.from_enumerable()
|> Flow.map(& :ets.lookup(table, &1))
|> Enum.to_list()
結果
- 15万件では特に Ecto:ETS=2:1 くらいの時間差だった。ETSが速い
- 今回は一回きりのアクセスで、
:ets.insert_new()
も計測に含めており、そちらに時間がかかっている面がある:ets.lookup
だけならば、4:1 くらいになった- 余談で、
insert_new()
をFlowでしてみたときに遅くなったのでひょっとすると何か変かもしれない- 追記:
write_concurrency
がデフォルトfalse
らしい - では
true
にすればいいかというと、、、?下記によると簡単な話ではなさそう
- 追記:
- 用途によっては、ETSを検討する価値がありそう
- 余談で
:ets.match()
は遅かった
- 余談で