:ets.select_count
seems much slower than manual counting using :ets.next
.
I filled the table (ordered set) with a million records with the keys {i, j}
, where i
and j
are integers in the range from 1
to 1000
inclusive.
Then I counted the number of records with keys greater than {500, 0}
and less than {599,: infinity}
(100k records).
defmodule Test do
def bench() do
set = :ets.new(:set, [:set])
ord = :ets.new(:ord, [:ordered_set])
Enum.each(1..1000, fn i ->
Enum.each(1..1000, fn j ->
r = {{i, j}, "#{i}-#{j}"}
:ets.insert(set, r)
:ets.insert(ord, r)
end)
end)
ms = [
{
{:"$1", :_},
[{:andalso, {:>, :"$1", {{500, 0}}}, {:<, :"$1", {{599, :infinity}}}}],
[true]
}
]
{set_time, 100_000} = :timer.tc(&:ets.select_count/2, [set, ms])
{ord_time, 100_000} = :timer.tc(&:ets.select_count/2, [ord, ms])
{ord_time_man, 100_000} = :timer.tc(&select_count/3, [ord, {500, 0}, {599, :infinity}])
IO.puts("set (select) - #{set_time}")
IO.puts("ordered_set (select) - #{ord_time}")
IO.puts("ordered_set (manual) - #{ord_time_man}")
end
def select_count(table, from, to) do
select_count(table, :ets.next(table, from), to, 0)
end
def select_count(table, from, to, res) when from < to do
select_count(table, :ets.next(table, from), to, res + 1)
end
def select_count(_table, _from, _to, res), do: res
end
Test.bench()
Results on my machine:
set (select) - 208715
ordered_set (select) - 121615
ordered_set (manual) - 15120
Is there a way to speed up :etc.select_count
?