2

ウガンダのジョシュです。私は mnesia 断片化されたテーブル (64 個の断片) を作成し、それを 9948723 レコードまで入力することができました。各フラグメントは、2 つのレプリカを持つ disk_copies タイプでした。現在、qlc (クエリ リスト内包表記) を使用すると、レコードの検索が遅すぎて、不正確な結果が返されていました。

このオーバーヘッドは、レコードを照合するためにテーブル全体をトラバースする mnesia の select 関数を qlc が使用することであることがわかりました。私は以下の何かを試しました。

-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 pentium 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 は、一致式、戻り値のチャンク サイズなどを定義するデータ構造です。

マッチ式を動的に構築しようとしたときに問題が発生しました。

関数 mnesia:read/1 または mnesia:read/2 では、主キーが必要です

QLC を効率的に使用して、断片化された大きなテーブル内のレコードを検索するにはどうすればよいでしょうか? 助けてください。

レコードのタプル表現を使用すると、コードのアップグレードが難しくなることはわかっています。これが、mnesia:select/1、mnesia:match_object/1 の使用を嫌い、QLC に固執したい理由です。QLC は、同じノード上であっても、64 個のフラグメントの mnesia テーブルからのクエリで間違った結果を返します。

断片化されたテーブルをクエリするために QLC を使用したことがある人はいますか? 助けてください

4

1 に答える 1

0

アクティビティコンテキストで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.
于 2012-08-20T08:26:30.820 に答える