使用 QLC 查询 mnesia 碎片表返回错误结果

发布于 2024-09-05 10:39:15 字数 2968 浏览 1 评论 0原文

我是乌干达的乔什。我创建了一个 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:表(选项卡,道具)。 其中 Props 是定义匹配表达式、返回值的块大小等的数据结构,

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

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

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

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

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

am josh in Uganda. i created a mnesia fragmented table (64 fragments), and managed to populate it upto 9948723 records. Each fragment was a disc_copies type, with two replicas.
Now, using qlc (query list comprehension), was too slow in searching for a record, and was returning inaccurate results.

I found out that this overhead is that qlc uses the select function of mnesia which traverses the entire table in order to match records. i tried something else below.

-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).

Trying this functionality gave me good results. But i found that i have to dynamically build patterns for every search that may be made in my stored procedures.

i decided to go through the havoc of doing this, so i wrote functions which will dynamically build wild patterns for my records depending on which parameter is to be searched.

%% 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). 

This was working very well though it was computationally intensive.
It could still work even after changing the record definition since at compile time, it gets the new record info

The problem is that when i initiate even 25 processes on a 3.0 GHz pentium 4 processor running WinXP, It hangs and takes a long time to return results.

If am to use qlc in these fragments, to get accurate results, i have to specify which fragment to search in like this.

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 was returning [], when i search for something yet when i use match_object/1 i get accurate results. I found that using match_expressions can help.

mnesia:table(Tab,Props).
where Props is a data structure that defines the match expression, the chunk size of return values e.t.c

I got a problem when i tried building match expressions dynamically.

Function mnesia:read/1 or mnesia:read/2 requires that you have the primary key

Now am asking myself, how can i efficiently use QLC to search for records in a large fragmented table? Please help.

I know that using tuple representation of records makes code hard to upgrade. This is why
i hate using mnesia:select/1, mnesia:match_object/1 and i want to stick to QLC. QLC is giving me wrong results in my queries from a mnesia table of 64 fragments even on the same node.

Has anyone ever used QLC to query a fragmented table?, please help

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

清欢 2024-09-12 10:39:15

您是否在活动上下文中调用 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.

Do you invoke the qlc in the activity context?

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文