LoginSignup
4
4

More than 5 years have passed since last update.

ETSのテーブルタイプ毎の書き込み時の違い

Posted at

「Elixir in Action」でETSについて読んだので、各テーブルタイプ(set, ordered_set, bag, duplicate_bag)毎の挙動の違いを調べた。言語はErlang/Elixirのどちらでもよいが、今回はElixirで書く。環境は以下。

Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.2.3) - press Ctrl+C to exit (type h() ENTER for help)

setとbagの違い

書き込み時に、同じキーの行がすでに存在するときの挙動が異なる。setは上書きを行い、bagは両方保持する。

set_table = :ets.new(:set_table, [:set])

:ets.insert(set_table, {:foo, 1})
:ets.insert(set_table, {:foo, 2})
:ets.lookup(set_table, :foo) #=> [foo: 2]


bag_table = :ets.new(:bag_table, [:bag])

:ets.insert(bag_table, {:foo, 1})
:ets.insert(bag_table, {:foo, 2})
:ets.lookup(bag_table, :foo) #=> [foo:1, foo: 2]

setとordered_setの違い

:ets.first/1, :ets.next/2, :ets.prev/2などで返ってくるキーの順番が異なる。setは内部で保持している順に返ってくるが、ordered_setはキーでソートしてある。

set_table = :ets.new(:set_table, [:set])

:ets.insert(set_table, {:foo, 1})
:ets.insert(set_table, {:bar, 2})
:ets.insert(set_table, {:baz, 3})
:ets.insert(set_table, {:hoge, 4})
:ets.insert(set_table, {:fuga, 5})

k = :ets.first(set_table)   #=> :bar
k = :ets.next(set_table, k) #=> :baz
k = :ets.next(set_table, k) #=> :fuga
k = :ets.next(set_table, k) #=> :hoge
k = :ets.next(set_table, k) #=> :foo
k = :ets.next(set_table, k) #=> :"$end_of_table"


ordered_set_table = :ets.new(:ordered_set_table, [:ordered_set])

:ets.insert(ordered_set_table, {:foo, 1})
:ets.insert(ordered_set_table, {:bar, 2})
:ets.insert(ordered_set_table, {:baz, 3})
:ets.insert(ordered_set_table, {:hoge, 4})
:ets.insert(ordered_set_table, {:fuga, 5})

k = :ets.first(ordered_set_table)   #=> :bar
k = :ets.next(ordered_set_table, k) #=> :baz
k = :ets.next(ordered_set_table, k) #=> :foo
k = :ets.next(ordered_set_table, k) #=> :fuga
k = :ets.next(ordered_set_table, k) #=> :hoge
k = :ets.next(ordered_set_table, k) #=> :"$end_of_table"

bagとduplicate_bagの違い

全く同じタプルを挿入したときの挙動が異なる。bagでは同じものとして扱われ1つしか残らないが、duplicate_bagでは別物として保持される。

bag_table = :ets.new(:bag_table, [:bag])

:ets.insert(bag_table, {:foo, 1})
:ets.insert(bag_table, {:foo, 1})
:ets.insert(bag_table, {:foo, 2})
:ets.lookup(bag_table, :foo) #=> [foo: 1, foo: 2]


duplicate_bag_table = :ets.new(:duplicate_bag_table, [:duplicate_bag])

:ets.insert(duplicate_bag_table, {:foo, 1})
:ets.insert(duplicate_bag_table, {:foo, 1})
:ets.insert(duplicate_bag_table, {:foo, 2})
:ets.lookup(duplicate_bag_table, :foo) #=> [foo: 1, foo: 1, foo: 2]

他にも読み出し(lookup, select, match)の速度や、:ets.safe_fixtable/2を使ったときの挙動に違いがある模様。結構深そう。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4