【问题标题】:Querying mnesia Fragmentated Tables using QLC returns wrong results使用 QLC 查询 mnesia Fragmentated Tables 返回错误结果
【发布时间】:2023-04-01 00:42:01
【问题描述】:

我在乌干达。我创建了一个 mnesia 碎片表(64 个碎片),并设法将其填充到 9948723 条记录。每个片段都是一个 disc_copies 类型,有两个副本。 现在,使用 qlc(查询列表理解),搜索记录太慢,并且返回不准确的结果。

我发现这个开销是 qlc 使用了 mnesia 的 select 函数,它遍历整个表以匹配记录。我在下面尝试了其他方法。

-define(ACCESS_MOD,mnesia_frag).
-define(DEFAULT_CONTEXT,transaction).
-define(NULL,'_').
-record(address,{tel,zip_code,email}).
-record(person,{name,sex,age,address = #address{}}).

match()-> Z = fun(Spec) -> mnesia:match_object(Spec) end,Z.

match_object(Pattern)->
    Match = match(),
    mnesia:activity(?DEFAULT_CONTEXT,Match,[Pattern],?ACCESS_MOD).

尝试这个功能给了我很好的结果。但我发现我必须为我的存储过程中可能进行的每次搜索动态构建模式。

我决定经历这样做的破坏,所以我编写了函数,这些函数将根据要搜索的参数为我的记录动态构建狂野模式。

%% This below gives me the default pattern for all searches ::= {person,'_','_','_'}

pattern(Record_name)->
    N = length(my_record_info(Record_name)) + 1,
    erlang:setelement(1,erlang:make_tuple(N,?NULL),Record_name).

%% this finds the position of the provided value and places it in that 
%% position while keeping '_' in the other positions.
%% The caller function can use this function recursively until
%% it has built the full search pattern of interest

pattern({Field,Value},Pattern_sofar)->
    N = position(Field,my_record_info(element(1,Pattern_sofar))),
    case N of
        -1 -> Pattern_sofar;
        Int when Int >= 1 -> erlang:setelement(N + 1,Pattern_sofar,Value);
        _ -> Pattern_sofar
    end.

my_record_info(Record_name)->
    case Record_name of
        staff_dynamic -> record_info(fields,staff_dynamic);
        person -> record_info(fields,person);
        _ -> []
    end.

%% These below,help locate the position of an element in a list
%% returned by "-record_info(fields,person)"

position(_,[]) -> -1;
position(Value,List)->
    find(lists:member(Value,List),Value,List,1).

find(false,_,_,_) -> -1;
find(true,V,[V|_],N)-> N;
find(true,V,[_|X],N)->
    find(V,X,N + 1).

find(V,[V|_],N)-> N;
find(V,[_|X],N) -> find(V,X,N + 1). 

虽然计算量很大,但效果很好。 即使更改了记录定义,它仍然可以工作,因为在编译时,它会获取新的记录信息

问题是,当我在运行 WinXP 的 3.0 GHz 奔腾 4 处理器上启动 25 个进程时,它会挂起并且需要很长时间才能返回结果。

如果要在这些片段中使用 qlc,为了获得准确的结果,我必须像这样指定要搜索的片段。

find_person_by_tel(Tel)->
  select(qlc:q([ X || X <- mnesia:table(Frag), (X#person.address)#address.tel == Tel])).

select(Q)->
case ?transact(fun() -> qlc:e(Q) end) of
    {atomic,Val} -> Val;
    {aborted,_} = Error -> report_mnesia_event(Error) 
end.

Qlc 正在返回 [],当我搜索某些内容时,当我使用 match_object/1 时,我得到了准确的结果。我发现使用 match_expressions 会有所帮助。

mnesia:table(Tab,Props)。 其中 Props 是一个数据结构,它定义了匹配表达式,返回值的块大小 e.t.c

我在尝试动态构建匹配表达式时遇到了问题。

函数 mnesia:read/1 或 mnesia:read/2 要求你有主键

现在我问自己,如何有效地使用 QLC 搜索大型碎片表中的记录?请帮忙。

我知道使用记录的元组表示会使代码难以升级。这就是为什么 我讨厌使用 mnesia:select/1, mnesia:match_object/1 并且我想坚持使用 QLC。即使在同一个节点上,QLC 也会在我的 64 个片段的 mnesia 表的查询中给出错误的结果。

有人用QLC查询分片表吗?请帮忙

【问题讨论】:

    标签: mnesia


    【解决方案1】:

    您是否在活动上下文中调用 qlc?

    tfn_match(Id) ->
        Search = #person{address=#address{tel=Id, _ = '_'}, _ = '_'},
        trans(fun() -> mnesia:match_object(Search) end).
    
    tfn_qlc(Id) ->
        Q = qlc:q([ X || X <- mnesia:table(person), (X#person.address)#address.tel == Id]),
        trans(fun() -> qlc:e(Q) end).
    
    trans(Fun) ->
        try Res = mnesia:activity(transaction, Fun, mnesia_frag),
        {atomic, Res}
        catch exit:Error ->
        {aborted, Error}
        end.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 1970-01-01
      • 2015-02-24
      • 2014-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多