mnesia数据库性能测试

  本测试是mnesia表存在于磁盘,每条记录10个字段,总长度为139B,在一个mnesia节点上进行。

                             插入单条(ms)         查询单条(ms)       删除单条(ms)      按ID更新一条记录的两个字段(ms)

1000000               0.0432                      0.124                        0.113                            0.523

100000                 0.0562                      0.114                       0.124                              0.517

10000                   0.0426                      0.103                       0.12                                0.238

 1000                    0.0374                      0.015                        0.13                                0.424

测试结论:查询和更新操作相对稳定,而插入单条记录的变化浮动较大,需要进一步研究,mnesia插入数据的原理。

测试代码如下:

%% @author zcc

%% @doc @todo Add description to test_mnesia.
-module(test).
-include_lib("eunit/include/eunit.hrl").
-include_lib("stdlib/include/qlc.hrl").
-compile(export_all).
%% ====================================================================
%% API functions
%% ====================================================================
-export([random_seed/3]).
-export([start/0,batch_insert/2,search_test/2]).
%单条记录139B
-record(user,{
      id, %4B
      phone,%11B
      type,%10B
      key,%72B
      para,%32B
      flag1,%2B
      flag2,%2B
      flag3,%2B
      flag4,%2B
      flag5 %2B
      }).
%% ====================================================================
%% Internal functions
%% ====================================================================
% 初始化
% 创建数据库和表
init() ->
 io:format("Initionate begins..........................~n"),
 Schema = mnesia:delete_schema([node()|nodes()]),%如果已创建,执行删除操作
    case Schema of
  ok ->
   io:format("Delete schema successfully~n");
  {error,Reason1} ->
   io:format("Delete schema failure:~w~n",[Reason1])
 end,
 Result1 = mnesia:create_schema([node()|nodes()]),%,创建节点,相当于数据库
 case Result1 of
  ok ->
   io:format("Create schema successfully~n");
  {error,Reason} ->
   io:format("Create schema failure~w~n",[Reason]);
  _Err->
   io:format("Create schema failure~n")
 end,
 %lists:foreach(fun(N) ->spawn(N, mnesia, start,[])end,[node()|nodes()]),
 batch_op(fun() -> mnesia:start() end),
 sleep(1000),
 {P,O} = mnesia:create_table(user,[{disc_copies,[node()]},{type,set},{attributes,record_info(fields,user)}]),
 %batch_op(fun() -> mnesia:create_table(agent,[{type,set},{attributes,record_info(fields,agent)}]) end),
 % {disc_copies,[node()]},{ram_copies,nodes()}, 根据record创建agent表
    case {P,O} of
  {atomic,ok} ->
           io:format("Create user table successfully^!^..........................~n");
  _Other ->
      %New = setelement(3, O, list_to_atom(element(3, O))),
      io:format("Create user failure:~w~n",[O])
 end,
    io:format("Initionate end..........................~n").
start() ->
    io:format("Start begins..........................~n"),
    init(),
 log4erl:conf("D:/ErlangWorkspace1/MnesiaTest/log4erl.conf"),
 %lists:foreach(fun(N) -> spawn(N, mnesia, wait_for_tables,[[agent],10000])end,[node()|nodes()]),
 batch_op(fun() -> mnesia:wait_for_tables([user],10000) end),
 io:format("Start end..........................~n").

%停止结束
stop() ->
 %lists:foreach(fun(N) ->spawn(N, mnesia, stop,[])end,[node()|nodes()]).
    P=fun start/0,
 P(),
 batch_op(fun()-> mnesia:stop() end).

%定义批量操作
batch_op(Op) ->
 lists:foreach(fun(N) ->
         Pid = spawn(N, fun() ->
           %%在每个节点做的事情
           Op()
            end)
        end,
                   [node()|nodes()]
   ).
%% ====================================================================
%% mnesia performance test API: mnesia性能测试
%% ====================================================================

%% 产生从start开始到end结束,(end-start+1)条记录
data_set(List,Start,End) ->
 case Start =:= End+1 of
  true ->
   List;
  false ->
   Result = List ++ [{user,
          <<Start:32>>,
          "13051234992",
          <<(Start+2147483648):80>>,
          <<(Start+2147483648):576>>,
          <<(Start+2147483648):256>>,
          <<Start:16>>,
          <<Start:16>>,
          <<Start:16>>,
          <<Start:16>>,
          <<Start:16>>}],
   case length(Result) =:= 1000000 of
         true -> io:format("length=~p~n",[length(Result)]);
      false -> ok
   end,
            data_set(Result,Start+1,End)
 end.

 %%填充数据库从Start到End,由Threads个线程来做

fill_db(Start,End,Threads) ->

    Interval = (End - Start +1) div Threads,

   Rem = (End - Start +1) rem Threads,

   allocate(Start,Interval,1,Threads),

   case Rem =:= 0 of

           true -> list_to_atom("executing insert,please waiting.........");

           false ->

                      spawn(test,batch_insert,[End-Rem+1,End])

   end.

allocate(Start,End,Interval,ThreadNum,Threads) ->

                 case  ThreadNum =:= Threads+1 of

                        true -> ok;

                       false -> 

                                  spawn(test,batch_insert,[Start,Start+Interval-1]),

                                  allocate(Start+Interval,Interval,ThreadNum+1,Threads)

                   end.

%%改进后的批插入

batch_insert(Start,End) ->

     F = fun() ->insert(Start,End) end,

    mnesia:transaction(F),

   io:format("inserted from ~p to ~p recoreds completedly~n",[Start,End]).

insert(Start,End) ->

      case Start =:= End+1 of

             true -> ok;

             false ->

                        mnesia:write({user,

                                            <<Start:32>>,

                                            "13050093456",

                                            <<(Start+2147483648):80>>,

                                           <<(Start+2147483648):576>>,

                                          <<(Start+2147483648):256>>,

                                         <<Start:16>>,

                                        <<Start:16>>,

                                       <<Start:16>>,

                                      <<Start:16>>,

                                      <<Start:16>>}),

%                   case Start of

 %                            1 ->io:format("inserted ~p records completed ~n",[Start]);

  %                         10000 ->io:format("inserted ~p records completed ~n",[Start]);

  %                        100000 ->io:format("inserted ~p records completed ~n",[Start]);

  %                        1000000 ->io:format("inserted ~p records completed ~n",[Start]);

 %                         _ -> ok

    %                 end,

                  insert(Start+1,End)

end.
%插入测试数据,此方法对于大数据运行性能较慢:首先产生dateset;然后再写入,当数据量大的时候,两个过程是非常耗时的,可以合并

在产生的同时,便写入,封装成一个事务操作,如上面的batch_insert 所示,如果写入mnesia的事务,频繁发生,则mnesia会报mnesia is overloaded警告
batch_insert(Start,End)->
    %mnesia:clear_table(agent),
    F = fun() ->
%%      lists:foreach(fun mnesia:write/1, data_set([],Start,End))
  lists:foldl(fun(A,Acc)-> mnesia:write(A),case Acc of
             1-> log4erl:info("inserted ~p records completed~n",[Acc]);
             10000 -> log4erl:info("inserted ~p records completed~n",[Acc]);
             20000 -> log4erl:info("inserted ~p records completed~n",[Acc]);
             30000 -> log4erl:info("inserted ~p records completed~n",[Acc]);
             100000 -> log4erl:info("inserted ~p records completed~n",[Acc]);
             200000 -> io:format("inserted ~p records completed~n",[Acc]);
             300000 -> io:format("inserted ~p records completed~n",[Acc]);
             400000 -> io:format("inserted ~p records completed~n",[Acc]);
             500000 -> io:format("inserted ~p records completed~n",[Acc]);
             600000 -> io:format("inserted ~p records completed~n",[Acc]);
             700000 -> io:format("inserted ~p records completed~n",[Acc]);
             800000 -> io:format("inserted ~p records completed~n",[Acc]);
             900000 -> io:format("inserted ~p records completed~n",[Acc]);
                   1000000 -> io:format("inserted ~p records completed~n",[Acc]);
                _ -> ok
             end,
                                                 Acc+1
              end, 0,data_set([],Start,End))
        end,
 mnesia:transaction(F).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% 测试本地节点mnesia查询性能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%利用read进行查找
find_user_ByItem(Item) ->
    F = fun() -> mnesia:read({user,Item}) end,
    {atomic,Result} = mnesia:transaction(F),
    Result.
%%按ID查询一次所花费的时间
search_onetime(Id) ->
 statistics(wall_clock),
 Result = apply(?MODULE,find_user_ByItem,[Id]),
 {_,TimeCost} = statistics(wall_clock),
 %{TimeCost,Result}=timer:tc(agent_table, find_agent_ByItem,[Id]),
 %io:fwrite("Time cost is:~w [ms]~n",[TimeCost]),
    %io:format("Result=~w~n",[Result]),
 TimeCost.
%% 找出1....Num中的N个不重复的随机数
random_seed(List,Hi,N) ->
 case N =:= length(List) of
       true ->
     List;
    false->
     P  = crypto:rand_uniform(1, Hi),
     case lists:member(P, List) of
           true ->
                  random_seed(List,Hi,N);
     false ->
      random_seed(List ++ [P],Hi,N)
        end
 end.

%% 查询num次所花费的总时间
batch_search_test(Hi,Num) ->
 List = random_seed([],Hi,Num),
    lists:foldl(fun(A,Acc) -> Acc+search_onetime(A) end, 0, List).

%从TotalRecord条记录中,查找出Num条记录,Flag为1表示从远程节点中取;为0从
search_test(TotalRecord,Num) ->
 TotalTime = batch_search_test(TotalRecord,Num),
 io:fwrite("Time cost of one time is:~w [ms]~n",[TotalTime/Num]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%% 测试插入性能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 测试插入Num条记录,Times次,取平均值
%% param:Num:记录条数;Times:测试次数
%% return:{total,aver}
insert_test(Start,End,Times) ->
 {Total,Ave}=insert_test2(Start,End,Times),
 %% 单条插入时间
 io:fwrite("Time cost is:~w [ms]~n",[Ave/1000/(End-Start+1)]).

insert_test2(Start,End,Times) ->
 %%结果是微秒
 {TimeCost,_Result} = timer:tc(?MODULE,batch_insert,[Start,End]),
 case Times of
  1 -> {TimeCost,TimeCost};
  N -> {OtherTimeCost,_OtherAvgTimeCost} = insert_test2(Start,End,N-1),
       {TimeCost+ OtherTimeCost,(TimeCost+OtherTimeCost)/N}
 end.
update(ID) ->
 statistics(wall_clock),
 %Q = qlc:q([X || X <- mnesia:table(user),X#user.id =:= <<ID:32>>]),
 %F = fun() -> qlc:e(Q) end,
 %{atomic,[Result]} = mnesia:transaction(F),
 %   NewKey = <<2147483648:576>>,
  % NewPara = <<2147483648:256>>,
  %  NewRes = Result#user{key=NewKey,para=NewPara},
%%  io:format("~p",[NewRes]),
% F1= fun() -> mnesia:write(NewRes) end,
% mnesia:transaction(F1),

%封装成单条事务,采用read方法更新

F = fun() ->  

   [Result] = mnesia:read({user,<<ID:32>>}),    

    NewKey = <<2147483648:576>>,
    NewPara = <<2147483648:256>>,
    NewRes = Result#user{key=NewKey,para=NewPara},
    mnesia:write(NewRes)

   end,

    mnesia:transaction(F),
    {_,TimeCost} = statistics(wall_clock),
 TimeCost.
%% 查询num次所花费的总时间
batch_update_test(Hi,Num) ->
 List = random_seed([],Hi,Num),
    lists:foldl(fun(A,Acc) -> Acc+update(A) end, 0, List).
%%@author zcc
%%@date   2013-11-25
%%@func   在TotalRecord条记录中,更新Num条记录取平均值 
update_test(TotalRecord,Num) ->
 TotalTime = batch_update_test(TotalRecord,Num),
 io:fwrite("Time cost of one time is:~w [ms]~n",[TotalTime/Num]).

delete(ID) ->

   statistics(wall_clock),

   F= fun() -> mnesia:delete({user,<<ID:32>>}) end,

  mnesia:transaction(F),

 {_,TimeCost} = statistics(wall_clock),

  TimeCost

generate_List(List,Num) ->

      case Num =:= 0 of

                true -> List;

               false ->

                         generate_List(List++[Num],Num-1)

     end.

%删除ID从1到Num的记录

delete_test(Num) ->

           List = generate_List([],Num),

          Time = lists:foldl(fun(A,Acc) -> Acc + delete(A) end,0,List),

          io:format("Time cost is :~w [ms] ~n",[Time/Num]).
sleep(I) ->
 receive after I -> ok end.
%% ====================================================================
%% eunit test
%% ====================================================================
search_test()->
 ?assert(ok  =:=io:format("I am Chinese!")),
 ?assert(1=/=2),
 ?assert(1=:=2).

%search_test() ->
% {TimeCost,Result}=timer:tc(agent_table, find_agent_ByItem,[1]),
% io:fwrite("Time cost is:~w [ms] Result=~w",[TimeCost,Result]).


%%附:eunit使用方法:
%%  (1)include,eunit的hrl文件;
%%  (2)方法名以"_test"后缀结束;
%%  (3)执行时eunit:test(Module)或Module:test()

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,我之前提到的`mnesia:write/1`函数是不正确的。 在Mnesia中,`mnesia:write/3`函数用于将数据写入到Mnesia数据库中的指定表中。它接受三个参数:表名、记录和写选项。 以下是使用`mnesia:write/3`函数的一般步骤: 1. 确保Mnesia数据库已启动:在使用`mnesia:write/3`函数之前,请确保Mnesia数据库已经启动并且相关表已创建。 2. 定义记录:创建一个记录,包含要插入或更新到Mnesia表中的数据。记录是一个以元组形式表示的数据结构。 3. 调用`mnesia:write/3`函数:使用`mnesia:write/3`函数将记录写入到Mnesia表中。例如: ```erlang Record = {table_name, Key, Value}, ok = mnesia:write(table_name, Record, write). ``` 在上面的示例中,`table_name`是要写入的Mnesia表的名称,`Key`是记录的主键,`Value`是要写入的数据。 第三个参数是写选项,可以指定为以下之一: - `write`:执行插入或更新操作。 - `write_dirty`:执行脏写操作,不关心事务。 - `write_concurrency`:执行并发写操作。 4. 错误处理:根据需要进行错误处理。如果写入操作失败,`mnesia:write/3`函数会抛出一个异常。 需要注意的是,`mnesia:write/3`函数将数据写入到内存中的Mnesia副本,并不会立即持久化到磁盘。如果需要将数据持久化到磁盘,可以使用`mnesia:transaction/1`函数包裹写操作,并在事务结束时调用`mnesia:commit/1`函数。 这只是一个简单的示例,实际使用中可能需要更复杂的逻辑和数据操作。建议参考Erlang和Mnesia的官方文档以获取更详细的信息和示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值