10

私は最近Erlangに飛び込んでいます.Mnesiaを使用してデータベースの作業を行うことにしました.Mnesiaはあらゆる種類のErlangデータ構造を問題なく格納でき、簡単にスケーリングでき、リスト内包表記で使用できるなど.

標準の SQL データベースの場合、ほとんどの行は主キー (通常は自動インクリメント整数) で識別できます。デフォルトでは、Mnesia は行の最初のフィールドをキーと見なします。また、私の知る限り、自動インクリメント整数キーを持つ方法もありません。

テーブルを表すこれらの架空のレコードがあるとします。

-record(user, {name, salt, pass_hash, email}).
-record(entry, {title, body, slug}).
-record(user_entry, {user_name, entry_title}).

エントリのタイトルのように、リソースを識別するために、ユーザー名を使用するだけで十分な場合もありますが、完全性を維持するにはどうすればよいでしょうか?

ユーザーが名前を変更したり、編集後にエントリのタイトルが変更されたりするとします。データが正しく関連付けられていることを確認するにはどうすればよいですか? ユーザー名が変更されたときにそれを使用してすべてのテーブルを更新することは、どのように配置されていてもひどい考えのように思えます。

Mnesia である種の主キーシステムを実装する最良の方法は何でしょうか?

また、最初のフィールドが通常キーである場合、「user_entry」のような中間テーブルはどのようになりますか? そうでなければ、Mnesia で多対多の関係を表現するより良い方法は何でしょうか?

4

2 に答える 2

9

自動インクリメント int を人工的な外部キーとして使用する代わりに、GUID を使用することを好みます。GitHub で利用可能なErlang uuid モジュールがあります。ドキュメントに次のよう{now(), node()}に記載されていることを考えると、now/0「この BIF への後続の呼び出しが継続的に増加する値を返すことも保証されています。」

主キーとして変更できるものを使用することは、データベース システムとは関係なく、悪い考えのように思えます。

Mnesia のデータを最初の正規形に正規化する必要がないことを忘れないでください。あなたの例では、次の構造を検討します。

-record(user, {id, name, salt, pass_hash, email, entries}).
-record(entry, {id, title, body, slug, users}).

とは IDentriesusersリストです。もちろん、これは必要なクエリによって異なります。

編集: 多対一ではなく多対多に修正されました。

于 2008-12-27T19:59:49.787 に答える
8

Mnesia は、 の形式のシーケンス (自動インクリメント整数) をサポートしていますmnesia:dirty_update_counter(Table, Key, Increment)。これを使用するには、Key と Count の 2 つの属性を持つテーブルが必要です。名前にかかわらず、dirty_update_counter はトランザクション内で実行されなくてもアトミックです。

Ulf Wiger は、彼のrdbms パッケージで mnesia の上に典型的な RDBMS 機能を提供する作業を行いました。彼のコードは、外部キー制約、パラメーター化されたインデックス、フィールド値の制約などを提供します。残念ながら、このコードは 2 年間更新されておらず、Erlang の経験がかなりなければ実行するのはおそらく難しいでしょう。

mnesia を設計して使用する場合、mnesia はリレーショナル データベースではないことに注意してください。これはトランザクション キー/バリュー ストアであり、正規化しない場合ははるかに使いやすくなります。

ユーザー名が一意である場合は、次のスキーマを使用できます。

-record(user, {name, salt, pass_hash, email}).
-record(entry, {posted, title, body, slug, user_name}).

posted記事がアップロードされた erlang:now() 時刻はどこにありますか。user_nameユーザーのすべての記事のリストを頻繁に取得する必要がある場合は、セカンダリ インデックスが必要になることがあります。このデータは 2 つのテーブルに分割されるため、アプリケーション コードで整合性制約を適用する必要があります (たとえば、有効な user_name のないエントリを受け入れないなど)。

mnesia の各フィールド値は任意の erlang 用語である可能性があるため、特定のフィールドの一意のキーが見つからない場合は、いくつかのフィールドを組み合わせて、常に一意の値を得ることができます - おそらく {Username, DatePosted、TimePosted}。Mnesia では、 を介して部分キーを検索できますmnesia:select(Table, MatchSpec)。MatchSpecs を手動で記述するのは非常に難しいためets:fun2ms/1、疑似 erlang 関数を matchspec に変換できることを覚えておいてください。

この例では、fun2ms はブログ エントリ テーブルを検索するための matchspec を生成します-record(entry, {key, title, slug, body}).。キーは、作成{Username, {Year, Month, Day}, {Hour, Minute, Second}}者のユーザー名と記事が投稿された日時です。TargetUsername以下の例では、 2008 年 12 月までにすべてのブログ投稿のタイトルを取得します。

ets:fun2ms(fun (#entry{key={U, {Y,M,_D}, _Time}, title=T})
             when U=:=TargetUsername, Y=:=2008, M=:=12 ->
               T
           end).
于 2008-12-28T14:04:28.893 に答える