mnesia有2种方式脏读数据,一种是以Key的方式用dirty_read(Tab, Key),一种是以其他建立索引的字段读取dirty_index_read(Tab, OtherKey, Position).最开始以为这两个的速度是一样的,结果一侧是发现第一种是第二种的将近3倍。测试是用1千万的数据,10万的进程并发访问。
测试用的代码:
-module (tm). -behaviour (gen_server). % APIs -export([start_link/0, find/1, find1/1, ct/0, ct1/0]). % gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record (test_mnesia, {userid, pid}). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). find(UserId) -> mnesia:dirty_read(test_mnesia, UserId). find1(UserId) -> mnesia:dirty_index_read(test_mnesia, UserId, #test_mnesia.pid). ct() -> tc:ct(tm, find, [<<"user_1@android">>], 100000). ct1() -> tc:ct(tm, find1, [<<"user_1@android">>], 100000). %% =================================================================== %% gen_server callbacks %% =================================================================== init([]) -> mnesia:stop(), mnesia:delete_schema([node()]), mnesia:create_schema([node()]), mnesia:start(), {atomic,ok} = mnesia:create_table(test_mnesia, [{ram_copies, [node()]}, {attributes, record_info(fields, test_mnesia)}]), {atomic,ok} = mnesia:add_table_index(test_mnesia, pid), loop(10000000), {ok, []}. handle_call(_Request, _From, State) -> {reply, nomatch, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVer, State, _Extra) -> {ok, State}. %% =================================================================== %% Internal functions %% =================================================================== loop(N) when N > 0 -> UserId = <<"user_", (integer_to_binary(N))/binary, "@android">>, mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId}), loop(N - 1); loop(0) -> ok.
tc的代码:
%% =================================================================== %% Author xiaotie %% 2015-07-30 %% 单进程循环测试:LoopTimes是循环次数 %% tc:t(Module, Function, ArgsList, LoopTimes). %% 多进程并发测试:SpawnProcessesCount是并发的进程数 %% tc:ct(Module, Function, ArgsList, SpawnProcessesCount). %% =================================================================== -module (tc). -export ([t/4, ct/4]). tc(M, F, A) -> {Microsecond, _} = timer:tc (M, F, A), Microsecond. distribution(List, Aver) -> distribution(List, Aver, 0, 0). distribution([H|T], Aver, Greater, Less) -> case H > Aver of true -> distribution(T, Aver, Greater + 1, Less); false -> distribution(T, Aver, Greater, Less + 1) end; distribution([], _Aver, Greater, Less) -> {Greater, Less}. %% =================================================================== %% test: one process test N times %% =================================================================== t(M, F, A, N) -> {Max, Min, Sum, Aver, Greater, Less} = loop ({M, F, A}, N), io:format ("=====================~n"), io:format ("execute [~p] times of {~p, ~p, ~p}:~n", [N, M, F, A]), io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]), io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]), io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]), io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]), io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]), io:format ("=====================~n"). loop({M, F, A}, N) -> loop ({M, F, A}, N, 1, 0, 0, 0, []). loop({M, F, A}, N, I, Max, Min, Sum, List) when N >= I -> Microsecond = tc (M, F, A), NewSum = Sum + Microsecond, if Max == 0 -> NewMax = NewMin = Microsecond; Max < Microsecond -> NewMax = Microsecond, NewMin = Min; Min > Microsecond -> NewMax = Max, NewMin = Microsecond; true -> NewMax = Max, NewMin = Min end, loop ({M, F, A}, N, I + 1, NewMax, NewMin, NewSum, [Microsecond|List]); loop({_M, _F, _A}, N, _I, Max, Min, Sum, List) -> Aver = Sum / N, {Greater, Less} = distribution(List, Aver), {Max, Min, Sum, Aver, Greater, Less}. %% =================================================================== %% Concurrency test: N processes each test one time %% =================================================================== ct(M, F, A, N) -> {Max, Min, Sum, Aver, Greater, Less} = cloop ({M, F, A}, N), io:format ("=====================~n"), io:format ("spawn [~p] processes of {~p, ~p, ~p}:~n", [N, M, F, A]), io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]), io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]), io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]), io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]), io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]), io:format ("=====================~n"). cloop({M, F, A}, N) -> CollectorPid = self(), ok = loop_spawn({M, F, A}, CollectorPid, N), collector(0, 0, 0, N, 1, []). loop_spawn({M, F, A}, CollectorPid, N) when N > 0 -> spawn_link(fun() -> worker({M, F, A}, CollectorPid) end), loop_spawn({M, F, A}, CollectorPid, N - 1); loop_spawn(_, _, 0) -> ok. collector(Max, Min, Sum, N, I, List) when N >= I -> receive {result, Microsecond} -> NewSum = Sum + Microsecond, if Max == 0 -> NewMax = NewMin = Microsecond; Max < Microsecond -> NewMax = Microsecond, NewMin = Min; Min > Microsecond -> NewMax = Max, NewMin = Microsecond; true -> NewMax = Max, NewMin = Min end, collector(NewMax, NewMin, NewSum, N, I + 1, [Microsecond|List]) after 10000 -> ok end; collector(Max, Min, Sum, N, _, List) -> Aver = Sum / N, {Greater, Less} = distribution(List, Aver), {Max, Min, Sum, Aver, Greater, Less}. worker({M, F, A}, CollectorPid) -> Microsecond = tc(M, F, A), CollectorPid ! {result, Microsecond}.
结果同时10万并发进程去访问find和find1,结果:
===================== spawn [100000] processes of {tm, find, [<<"user_1@android">>]}: Maximum: 1686(μs) 0.001686(s) Minimum: 1(μs) 1.0e-6(s) Sum: 237287(μs) 0.237287(s) Average: 2.37287(μs) 2.3728699999999998e-6(s) Greater: 28017 Less: 71983 ===================== ok 3> tm:ct1(). ===================== spawn [100000] processes of {tm, find1, [<<"user_1@android">>]}: Maximum: 1862(μs) 0.001862(s) Minimum: 4(μs) 4.0e-6(s) Sum: 741330(μs) 0.74133(s) Average: 7.4133(μs) 7.4133e-6(s) Greater: 29711 Less: 70289 =====================
测了几次 基本dirty_read在2微秒左右,dirty_index_read在7微秒左右。性能在3倍左右。
总结:
经过测试,我们用mnesia想快速读取数据的时候尽量把总查的字段作为Key。
相关推荐
4.3.脏操作 4.4.记录名与表 4.5.作业(Activity)概念和多种存取上下文 4.6.嵌套事务 4.7.模式匹配 4.8.迭代 5、其它.Mnesia.特性 5.1.索引 5.2.分布和容错 5.3.表分片 5.4.本地内容表 5.5.无盘...
Management System, appropriate for telecommunications applications and other Erlang applications which require continuous operation and soft real-time properties. It is one section of the Open Telecom...
Mnesia是一个分布式数据库管理系统,适合于电信和其它需要持续运行和具备软实时特性的Erlang应用,越来越受关注和使用,但是目前Mnesia资料却不多,很多都只有官方的用户指南。下面的内容将着重说明 如何做 Mnesia ...
erlang-mnesia-19.3.6.4-1.el7.x86_64.rpm
erlang的高性能集群服务器,erlang解决方案。 供大家学习使用
Examples are included how to start an Erlang session, specify a Mnesia database directory, initialize a database schema, start Mnesia, and create tables. Initial prototyping of record definitions is ...
在摸索过一段时间Erlang文档后,笔者开始走向了Erlang网络连接的性能调优之旅。本文详细记录了笔者走向Erlang网络编程性能调优之旅的每个脚印。
java php python erlang 千万级内存数据性能比较,
erlang系统自带的数据库mnesia的官方文档。
Mnesia是一个分布式数据库管理系统(DBMS),适合于电信和其它需要持续运行和具备软实时 特性的Erlang应用。
使用erlang进行UDP测试,这几个是为了凑够20字。
erlang高性能网络库esockd的编译和使用,erlang高性能网络库esockd的编译和使用
Mnesia是一个分布式数据库管理系统(DBMS),适合于电信和其它需要持续运行和具备软实时特性的Erlang应用,是构建电信应用的控制系统平台——开放式电信平台(OTP)的一部分。
oracle性能预测
Mnesia table fragmentation 过程及算法分析。erlang就算在64位下dets的空间限制仍旧是2g,同样影响了mnesia,如果有更大需求,就必须使用Mnesia的 table fragmentation 技术
erlang入门电子书 erlang编程 Introducing Erlang,作者Simon.St.Laurent
分析erlang的VM, 性能的定量分析,编码最佳实践, 工具介绍都在这里。
erlang 安装包
高性能集群服务器Erlang解决方案
Mnesia是一个分布式数据库管理系统(DBMS),适合于电信和其它需要持续运行和具备软实时特性的Erlang应用。 目 录 1 、介绍 . . .. . .. . . .. . 4 1.1 关于 Mnesia . . .. . .. . . .. . 4 1.2 Mnesia ...