Just a small example to show the performance difference between a $X bound match and a value match in the match spec.
Eshell V13.0 (abort with ^G)
1> ets:new(test, [named_table, ordered_set, {keypos, 1}]).
test
2> [ets:insert(test, {X,X}) || X <- lists:seq(1,1_000_000)].
[true,true,true,true,true,true,true,true,true,true,true,
true,true,true,true,true,true,true,true,true,true,true,true,
true,true,true,true,true,true|...]
3> ets:fun2ms(fun({I, Content}) when I == 1_000_000 -> {I, [mark | Content]} end).
[{{'$1','$2'},[{'==','$1',1000000}],[{{'$1',[mark|'$2']}}]}]
4> ManualMs = [{{1_000_000,'$1'},[],[{{1_000_000,[mark|'$1']}}]}].
[{{1000000,'$1'},[],[{{1000000,[mark|'$1']}}]}]
5> Ms = [{{'$1','$2'},[{'==','$1',1000000}],[{{'$1',[mark|'$2']}}]}].
[{{'$1','$2'},[{'==','$1',1000000}],[{{'$1',[mark|'$2']}}]}]
6> [io:format("~p~n", [timer:tc(fun() -> ets:select(test, Ms) end)]) || _ <- lists:seq(1,10)].
{132734,[{1000000,[mark|1000000]}]}
{126449,[{1000000,[mark|1000000]}]}
{121694,[{1000000,[mark|1000000]}]}
{122800,[{1000000,[mark|1000000]}]}
{120502,[{1000000,[mark|1000000]}]}
{115237,[{1000000,[mark|1000000]}]}
{117500,[{1000000,[mark|1000000]}]}
{114709,[{1000000,[mark|1000000]}]}
{125850,[{1000000,[mark|1000000]}]}
{128768,[{1000000,[mark|1000000]}]}
[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok]
7> [io:format("~p~n", [timer:tc(fun() -> ets:select(test, ManualMs) end)]) || _ <- lists:seq(1,10)].
{19,[{1000000,[mark|1000000]}]}
{4,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{4,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
{3,[{1000000,[mark|1000000]}]}
[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok]
8>
And in case you were wondering about duplicate_bag
Eshell V13.0 (abort with ^G)
1> ets:new(test, [named_table, duplicate_bag, {keypos, 1}]).
test
2> [ets:insert(test, {case (X rem 1000) =:= 0 of true -> moo; false -> X end, X}) || X <- lists:seq(1,1_000_000)].
[true,true,true,true,true,true,true,true,true,true,true,
true,true,true,true,true,true,true,true,true,true,true,true,
true,true,true,true,true,true|...]
3> Ms = ets:fun2ms(fun({I, Content}) when I == moo -> {I, [mark | Content]} end).
[{{'$1','$2'},[{'==','$1',moo}],[{{'$1',[mark|'$2']}}]}]
4>
4> ManualMs = [{{moo,'$1'},[],[{{moo,[mark |'$1']}}]}].
[{{moo,'$1'},[],[{{moo,[mark|'$1']}}]}]
5>
5> {MsTime, MsTimes} = lists:foldl(fun(_, {T0, Times}) -> {T1, _} = timer:tc(fun() -> ets:select(test, Ms) end), {T0 + T1, [T1 | Times]} end, {0, []}, lists:seq(1,10)).
{2060486,
[205817,203358,210674,201202,198532,200487,207024,208889,
205530,218973]}
6> lists:foreach(fun(T) -> io:format("~w~n", [T]) end, MsTimes).
205817
203358
210674
201202
198532
200487
207024
208889
205530
218973
ok
7> io:format("MsTime Avg: ~w~n", [MsTime / 10]).
MsTime Avg: 206048.6
ok
8> {ManualMsTime, ManualMsTimes} = lists:foldl(fun(_, {T0, Times}) -> {T1, _} = timer:tc(fun() -> ets:select(test, ManualMs) end), {T0 + T1, [T1 | Times]} end, {0, []}, lists:seq(1,10)).
{1140,"jkj{abe[ZÝ"}
9> lists:foreach(fun(T) -> io:format("~w~n", [T]) end, ManualMsTimes).
106
107
106
123
97
98
101
91
90
221
ok
10> io:format("ManualMsTime Avg: ~w~n", [ManualMsTime / 10]).
ManualMsTime Avg: 114.0
ok