2016-02-13 73 views
3

簡潔而甜美;我正在建立一個新項目,我可以用返回ETS,但我寧願回到Mnesia--由於內置交易等可能派上用場的東西。 I 不需要關心複製和擴展到其他節點,這就是爲什麼我認爲Mnesia的性能在ETS上有開銷。在Elixir/Erlang的(本地)Mnesia實例中實現最佳寫入性能

zackehh:~/GitHub/my_project$ MIX_ENV=test mix bench 
Settings: 
    duration:  1.0 s 

## BasicBench 
[19:24:15] 1/4: retrieve key hit mnesia 
[19:24:23] 2/4: retrieve key hit 
[19:24:30] 3/4: insert new key mnesia 
[19:24:33] 4/4: insert new key 

Finished in 25.24 seconds 

## BasicBench 
insert new key     10000000 0.63 µs/op 
retrieve key hit    10000000 0.64 µs/op 
retrieve key hit mnesia  10000000 0.69 µs/op 
insert new key mnesia   500000 4.70 µs/op 

我跑了幾個(本地)的基準,並且很明顯,Mnesia的是讀PERF相媲美,但寫PERF慢得多。我想知道是否有任何方法來加速它(例如關閉複製檢查等)。

附加信息:

Mnesia的表:

[ 
    { :ram_copies, [node()] }, 
    { :local_content, true }, 
    { :attributes, [:key,:value] } 
] 

測試

  • ETS操作使用:ets.lookup/2:ets.insert/2
  • Mnesia的操作使用:mnesia.dirty_write/1:mnesia.dirty_read/2

我一直在用拖網捕小時,沒有任何的文檔已經跳出了作爲一個潛在的方法來加快這 - 所以我可能會盯着一個PERF牆,但如果有人能澄清/確認/建議,這將不勝感激。

回答

3

短的答案:

雖然,Mnesia使用ETS作爲發動機用於非持久性數據存儲(ram_copies表)但Mnesia的用於如果所選擇的表被複制或具有指數檢查的開銷使得它比ETS慢在寫新的記錄。

Documentation

對於非持久性數據庫存儲,更喜歡的Mnesia local_content表ETS表。與Ets寫道相比,即使是Mnesia的dirty_write操作也有固定的開銷。 Mnesia必須檢查表是否被複制或具有索引,這涉及每個dirty_write至少一次Ets查找。因此,Ets的寫作總是比Mnesia寫的要快。

但是你可以考慮mnesia:ets/2從ETS的表現在你的Mnesia表中受益:

mnesia:ets(Fun, [, Args]) -> ResultOfFun | exit(Reason) 

Documentation

mnesia:ets/2在原始背景是調用樂趣不受交易保護。 Mnesia函數調用在Fun中執行,並直接在本地ets表上執行,前提是本地存儲類型爲ram_copies,並且表不會複製到其他節點。訂閱不會被觸發,檢查點也不會更新,但速度非常快。如果所有操作都是隻讀的,則該函數也可以應用於disc_copies表。有關詳細信息,請參閱mnesia:activity/4和用戶指南。


編輯:我寫了一個基準,並在我的機器上運行它澄清中mnesia:ets/1mnesia:dirty_write/1ets:insert/2粗糙的差異。

mnesia_ets(Limit) -> 
    application:ensure_started(mnesia), 
    mnesia:create_table(foo, [{ram_copies, [node()]}]), 
    WriteFun = fun() -> 
     [mnesia:write({foo, I, I}) || I <- lists:seq(1, Limit)] 
    end, 
    timer:tc(fun() -> mnesia:ets(fun() -> WriteFun() end) end). 

ets(Limit) -> 
    ets:new(bar, [named_table, public]), 
    WriteFun = fun() -> 
     [ets:insert(bar, {bar, I, I}) || I <- lists:seq(1, Limit)] 
    end, 
    timer:tc(fun() -> WriteFun() end). 

mnesia(Limit) -> 
    application:ensure_started(mnesia), 
    mnesia:create_table(baz, [{ram_copies, [node()]}]), 
    WriteFun = fun() -> 
     [mnesia:dirty_write({baz, I, I}) || I <- lists:seq(1, Limit)] 
    end, 
    timer:tc(fun() -> WriteFun() end). 

而且結果寫10000000記錄如下:

  • 4303992微秒ets:insert/2
  • 15911681微秒mnesia:ets/1
  • 29798736微秒mnesia:dirty_write/1

所以我能夠 由於上述原因,得出mnesia:ets/1mnesia:dirty_write/1更快,但它仍然比ets:insert/2慢。

+0

我看到了有關的東西:mnesia.ets,你可以提供一個例子嗎?我不太明白它在功能上需要什麼 - Mnesia呼叫? – whitfin

+1

@zackehh Mnesia的一些函數像'mnesia:write/1'一樣是上下文敏感的。所以如果你把它封裝在一個'fun'裏面,並且把這個函數傳遞給'mnesia:ets/1',它將直接在本地ets表上執行,而沒有這樣的開銷。例如:'mnesia:ets(fun() - > mnesia:write({table_name,key_1,val_1})end)'。 –

+0

知道了,試了一下,速度較慢:p感謝這個建議,但我想打開該上下文與使用上下文節省的成本一樣。好吧! – whitfin

2

正如Hamidreza Soleimani所指出的,Mnesia總是比ETS慢,而ETS在大多數情況下並不是問題。只是想指出另一種可能性。我不知道它是否會幫助你的情況,但總是值得一看。

Erlang Factory的這張幻燈片介紹了一種實現mnesia自定義支持的方法。它可能(或不可能)允許您在比較ETS時跳過減慢Mnesia的檢查。

http://www.erlang-factory.com/static/upload/media/143415340626199euc2015mnesialeveldb.pdf