qlc の速度

qlc と select どっちがいいのかなぁと。qlc は可読性が上がるので使いたいなと。
速度低下すらしなければ qlc を使った方がいいのかなぁという結果です。

大量のデータの場合は qlc だろうが select だろうが変わらないようですが、数千件であれば select のほうが早いようです。
select は可読性が一気にさがるので余り好きじゃないのですが、まぁコメントでカバーするべきなのかもしれません。

一応コードは動きますが、保証はできません。

-module(ets_test).

-compile(export_all).

-record(store, {key, value1, value2}).

-include_lib("stdlib/include/qlc.hrl").

main() ->
  ok.

test_qlc() ->
  Q = qlc:q([ {X#store.key, X#store.value1} ||
      X <- ets:table(store_table), X#store.value1 > 950]),
  qlc:e(Q).

test_select() ->
  ets:select(store_table,
    [{ #store{key='$1', value1='$2', value2='_'},
        [{'>', '$2', 950}], [ {{'$1','$2'}} ] }]).

test() ->
  ets:new(store_table, [set, public, named_table, {keypos, 2}]),
  lists:foreach(
    fun(A) ->
      K = "key_" ++ erlang:integer_to_list(A),
      V1 = random:uniform(1000),
      V2 = random:uniform(1000),
      ets:insert(store_table, #store{key=K, value1=V1, value2=V2})
  end, lists:seq(1, 30000)),
  Tmp1 = test_select(),
  {Time1, Value1} = timer:tc(?MODULE, test_select, []),
  io:format("select: ~p\ncount: ~p\n", [Time1, erlang:length(Value1)]),
  %erlang:display(Time1),
  %erlang:display(Tmp1),
  Tmp2 = test_qlc(),
  {Time2, Value2} = timer:tc(?MODULE, test_qlc, []),
  io:format("qlc: ~p\ncount: ~p\n", [Time2, erlang:length(Value2)]),
  %erlang:display(Time2),
  %erlang:display(Tmp2),
  ets:delete(store_table),
  ok.

適当な補足説明

qlc については「プログラミング Erlang」に色々サンプルが載ってるので言うことは特にないですが。
自分が良く忘れるので、メモ。

  • include_lib("stdlib/include/qlc.hrl") をすること
  • ets / dets / mnesia に対して使える
  • ets:table, dets:table, mnesia:table で呼び出すのが基本。
  • リスト内包表記を使う。
  • andalso とかも使える、ガードは基本全部使える。
  • クエリーの結合も可能。qlc:append(Q1, Q2) など。
  • 色々できます。
    • {compressed, bool()} | {no_files, NoFiles} | {order, Order} | {size, Size} | {tmpdir, TempDirectory} | {unique, bool()}

というか qlc は自分のためにも一度まとめよう。