友情データベース構造の設計:複数値列を使用する必要がありますか?


9

User_FriendList次の特性を持つと呼ばれるテーブルがあるとします。

CREATE TABLE User_FriendList (
    ID ...,
    User_ID...,
    FriendList_IDs...,
    CONSTRAINT User_Friendlist_PK PRIMARY KEY (ID)
);

また、上記の表に次のデータが含まれているとします。

 + ---- + --------- + --------------------------- +
 | ID | User_ID | Friendlist_IDs             |
 + ---- + --------- + --------------------------- +
 | 1 | 102 | 2:15:66:35:26:17:|
 + ---- + --------- + --------------------------- +
 | 2 | 114 | 1:12:63:33:24:16:102 |
 + ---- + --------- + --------------------------- +
 | 3 | 117 | 6:24:52:61:23:90:97:118 |
 + ---- + --------- + --------------------------- +

注:「:」場合(コロン)はデリミタである爆発にPHPでarray

ご質問

そう:

  • これは、「店舗」に便利な方法ですIDsFriendList

  • または、代わりに、FriendIdそれぞれに単一の値のみが含まれる個別の行が必要です。特定のリストのすべての行を取得する必要がある場合は、次のようなクエリを実行しますSELECT * FROM UserFriendList WHERE UserId = 1か?


3
:私はあなたがこの読み取りをお勧めしますstackoverflow.com/questions/3653462/...
tombom

IDを使用して何も計画しておらず、特にデータの品質を気にしない限り、IDを保存するのに多少便利な方法です。
mustaccio

codedodle.com/2014/12/social-network-friends-database.htmlが最良の解決策の1つになると思います。
グプタ

回答:


19

個々の情報を管理する

あなたのビジネスドメインで

  • ユーザーは、ゼロ・ワン・オア・多く持つことができる友達を
  • 友達は、最初に登録する必要がありますユーザー。そして
  • フレンドリストの単一の値を検索、追加、削除、または変更します。

次に、複数値列に収集された特定のデータは、非常に正確な意味を持つ個別の情報Friendlist_IDs表します。したがって、上記の列

  • 明示的な制約の適切なグループを伴い、
  • その値は、いくつかの関係演算(またはそれらの組み合わせ)によって個別に操作される可能性があります。

簡潔な答え

したがって、あなたは、各保持すべきであるFriendlist_IDs(B)を表すテーブル内の行ごとに排他的に1唯一値を受け付けるカラム()の値を概念レベルの間で行うことができる関連タイプユーザー、すなわち、友達 -as以下のセクションで例を示します。

このようにして、(i)上記の表を数学的関係として扱い、(ii)上記の列を数学的関係属性として扱うことができます(もちろん、MySQLとそのSQL方言が許可する限り)。

どうして?

E. F.コッド博士が作成したデータリレーショナルモデルでは、該当するドメインまたはタイプの値を行ごとに1つだけ保持する列で構成されるテーブルが必要です。したがって、問題のドメインまたはタイプの複数の値を含むことができる列を持つテーブルを宣言すると、(1)は数学的な関係を表せず、(2)前述の理論的フレームワークで提案された利点を得ることができなくなります。

ユーザー間の友情のモデリング:最初にビジネス環境のルールを定義する

何よりもまず、関連するビジネスルールの定義に基づいて、対応する概念スキーマをデータベースで区切ることを強くお勧めします。これは、他の要因の中でも、関心のある異なる側面間に存在する相互関係のタイプを記述する必要があります。 、該当するエンティティタイプとそのプロパティ。例えば:

  • ユーザーは、主に彼または彼女で識別されるユーザーID
  • ユーザーは、交互に彼または彼女の組み合わせによって識別されるのFirstNameLastNameの性別、および生年月日
  • ユーザーは、交互に、彼または彼女で識別されるユーザー名
  • ユーザーは、あるリクエスタゼロ-1-または-多くの友情
  • ユーザーはある届け先ゼロ-1-または-多くの友情
  • A 友情は、主にその組み合わせによって識別されRequesterIdとそのAddresseeId

解説IDEF1X図

このようにして、図1に示すIDEF1X 1ダイアグラムを導き出すことができました。これは、以前に定式化されたほとんどのルールを統合しています。

図1.ユーザーの友情IDEF1Xの図

図示されているように、要求者宛先は、特定の友情に参加する特定のユーザーが実行する役割を表す表示です。

そのため、Friendshipエンティティタイプは、同じエンティティタイプ、つまりUserのさまざまなオカレンスを伴う可能性のある多対多(M:N)カーディナリティ比の関連付けタイプを表します。そのため、これは「部品表」または「部品の爆発」として知られている古典的な構成の例です。


1 情報モデリングの統合定義 IDEF1X)は、1993年12月に米国国立標準技術研究所(NIST)によって標準として確立された非常に推奨される手法です。これは、(a)リレーショナルモデルの唯一の創始者、つまり EF Codd博士によって作成された初期の理論的資料にしっかりと基づいています。(b) PP Chen博士によって作成された、データのエンティティ関係ビュー。また、(c)Robert G. Brownが作成した論理データベース設計手法についても説明します。


例示的なSQL-DDL論理設計

次に、上記のIDEF1Xダイアグラムから、以下のようなDDL配置を宣言する方がはるかに「自然」です。

-- You should determine which are the most fitting 
-- data types and sizes for all the table columns 
-- depending on your business context characteristics.

-- At the physical level, you should make accurate tests 
-- to define the mostconvenient INDEX strategies based on 
-- the pertinent query tendencies.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions. 

CREATE TABLE UserProfile ( -- Represents an independent entity type.
    UserId          INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    BirthDate       DATE     NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    Username        CHAR(20) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- Single-column ALTERNATE KEY.
);

CREATE TABLE Friendship ( -- Stands for an associative entity type.
    RequesterId     INT      NOT NULL,
    AddresseeId     INT      NOT NULL, -- Fixed with a well-delimited data type.
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Friendship_PK            PRIMARY KEY (RequesterId, AddresseeId), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipToRequester_FK FOREIGN KEY (RequesterId)
        REFERENCES UserProfile (UserId),
    CONSTRAINT FriendshipToAddressee_FK FOREIGN KEY (AddresseeId)
        REFERENCES UserProfile (UserId)
);

このように:

  • ベーステーブルは個々のエンティティタイプを表します。
  • は、それぞれのエンティティタイプの単一のプロパティを表します。
  • 特定のデータ型aは、に含まれるすべてのが、INT、DATETIME、CHARなどの特定の明確に定義されたセットに属していることを保証するために固定されています。そして
  • すべてのテーブルに保持されているの形式のアサーションが概念スキーマで決定されたビジネスルールを確実に満たすように、複数の制約bが(宣言的に)構成されます。

単一値列の利点

示されているように、たとえば次のことができます。

  • 列への参照を作成するFOREIGN KEY(簡略化のためのFK)として制約することにより、すべての値が既存の行を指すことが保証されるため、列に対してデータベース管理システム(簡略化のためにDBMS)によって適用される参照整合性を利用します。Friendship.AddresseeIdUserProfile.UserId

  • 作成複合 PRIMARY KEY(PK)をカラムの組み合わせで構成された(Friendship.RequesterId, Friendship.AddresseeId)エレガントなすべて挿入された行を区別して、自然に、彼らの保護に貢献し、一意性を

    もちろん、これは、システムによって割り当てられたサロゲート値(たとえば、Microsoft SQL ServerのIDENTITYプロパティまたはMySQL のAUTO_INCREMENT属性で設定されたもの)の追加の列のアタッチメントと補助INDEXがまったく不要であることを意味します。

  • 保持する値をFriendship.AddresseeId正確なデータ型c(たとえば、UserProfile.UserIdこの場合INT に対して確立されたものと一致する必要があります)に制限し、DBMSが適切な自動検証を処理できるようにします。

    この要素は、(a)対応する組み込み型関数の利用、および(b)ディスク領域の使用の最適化にも役立ちます。

  • これらの物理要素は、列に関連するクエリの高速化に実質的に役立つため、列に小さくて高速な下位INDEXを構成することにより、物理レベルでデータ取得を最適化します。Friendship.AddresseeId

    確かに、あなたは、例えば、のための単一列のINDEX我慢することができますFriendship.AddresseeIdだけでは、包含することを複数列の1 Friendship.RequesterIdFriendship.AddresseeId、またはその両方を。

  • 同じ列内で一緒に収集される個別の値を「検索」することによって導入される不必要な複雑さを回避します(重複、誤ったタイプなどの可能性が高い)。リソースと時間のかかる非リレーショナルメソッドに頼って、このタスクを実行する必要があります。

したがって、各テーブル列のタイプdを正確にマークするために、関連するビジネス環境を注意深く分析する必要がある複数の理由があります。

説明したように、データベース設計者が果たす役割は、(1)リレーショナルモデルによって提供される論理レベルの利点、および(2)選択したDBMSによって提供される物理メカニズムを最大限に活用するために最も重要です。


abcd明らかに、DOMAINの作成(独特のリレーショナル機能)をサポートするSQLプラットフォーム( Firebird PostgreSQLなど)で作業する場合、それぞれに属する値のみを受け入れる列を宣言できます(適切に制約され、時々共有)ドメイン。


検討中のデータベースを共有する1つ以上のアプリケーションプログラム

arraysデータベースにアクセスするアプリケーションプログラムのコードで使用する必要がある場合は、関連するデータセットを完全に取得し、それを関連するコード構造に「バインド」するか、または実行するだけです。実行する必要のある関連するアプリプロセス。

単一値列のその他の利点:データベース構造の拡張ははるかに簡単です

AddresseeIdデータポイントを予約済みの適切に型指定された列に保持するもう1つの利点は、以下で例示するように、データベース構造の拡張が大幅に容易になることです。

シナリオの進行:フレンドシップステータスの概念の組み込み

以来友情は、時間の経過とともに進化することができますは、このようにあなたがしなければならない、このような現象を追跡する必要があるかもしれません(私は)概念スキーマを拡張すると、(ii)論理的なレイアウトで、いくつかの複数のテーブルを宣言します。そこで、次のビジネスルールを整理して、新しい法人の概要を説明します。

  • A 友情は 1対多の保持FriendshipStatusesを
  • A FriendshipStatusは、主にその組み合わせによって識別さRequesterId、そのAddresseeIdそのSpecifiedDateTime
  • ユーザー指定するゼロから一または多FriendshipStatuses
  • ステータス分類はゼロ-1-または多FriendshipStatusesを
  • ステータスは、主にで識別されるのStatusCode
  • ステータスは交互にそのによって識別される名前

拡張IDEF1X図

続いて、前のIDEF1Xダイアグラムを拡張して、上記の新しいエンティティタイプと相互関係タイプを含めることができます。新しい要素に関連付けられている以前の要素を表す図を図2に示します

図2.友情ステータスIDEF1Xダイアグラム

論理構造の追加

その後、次の宣言を使用してDDLレイアウトを長くすることができます。

--
CREATE TABLE MyStatus ( -- Denotes an independent entity type.
    StatusCode CHAR(1)  NOT NULL,
    Name       CHAR(30) NOT NULL,
    --
    CONSTRAINT MyStatus_PK PRIMARY KEY (StatusCode),
    CONSTRAINT MyStatus_AK UNIQUE      (Name) -- ALTERNATE KEY.
); 

CREATE TABLE FriendshipStatus ( -- Represents an associative entity type.
    RequesterId       INT      NOT NULL,
    AddresseeId       INT      NOT NULL,
    SpecifiedDateTime DATETIME NOT NULL,
    StatusCode        CHAR(1)  NOT NULL,
    SpecifierId       INT      NOT NULL,
    --
    CONSTRAINT FriendshipStatus_PK             PRIMARY KEY (RequesterId, AddresseeId, SpecifiedDateTime), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipStatusToFriendship_FK FOREIGN KEY (RequesterId, AddresseeId)
        REFERENCES Friendship  (RequesterId, AddresseeId), -- Composite FOREIGN KEY.
    CONSTRAINT FriendshipStatusToMyStatus_FK   FOREIGN KEY (StatusCode)
        REFERENCES MyStatus    (StatusCode),
    CONSTRAINT FriendshipStatusToSpecifier_FK  FOREIGN KEY (SpecifierId)
        REFERENCES UserProfile (UserId)      
);

その結果、特定の友情のステータスを最新にする必要があるたびに、ユーザーは新しい行を挿入するだけで済みますFriendshipStatus

  • 適当RequesterIdAddresseeId関連から-taken値はFriendship行優先。

  • 新しい意味のあるStatusCode価値MyStatus.StatusCode— から引き出されます—;

  • 正確なINSERTionインスタント、つまり、SpecifiedDateTime信頼できる方法でそれを取得して保持できるように、サーバー関数を使用することが望ましい。そして

  • SpecifierIdそれぞれを示すことになる値は、UserIdという新しいを入力しFriendshipStatus(複数可)facilities-のアプリの助けを借りて、-ideallyシステムに。

その範囲で、MyStatusテーブルに次のデータが含まれているとします。PK値は(a)エンドユーザー、アプリプログラマ、およびDBAに適しており、(b)物理実装レベルのバイト数が小さくて高速です。 —:

 + -——————————- + -—————————- +
 | StatusCode | 名前       |
 + -——————————- + -—————————- +
 | R | リクエストされた|
 + ------------ + ----------- +
 | A | 受け入れられる|
 + ------------ + ----------- +
 | D | 拒否されました|
 + ------------ + ----------- +
 | B | ブロケ|
 + ------------ + ----------- +

したがって、FriendshipStatusテーブルは以下に示すようなデータを保持する可能性があります。

 + -———————————- + -———————————- + -————————————————————— ———- + -——————————- + -———————————- +
 | RequesterId | AddresseeId | SpecifiedDateTime        | StatusCode | SpecifierId |
 + -———————————- + -———————————- + -————————————————————— ———- + -——————————- + -———————————- +
 | 1750 1748 | 2016-04-01 16:58:12.000 | R | 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 | 2016-04-02 09:12:05.000 | A | 1748 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 | 2016-04-04 10:57:01.000 | B | 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 | 2016-04-07 07:33:08.000 | R | 1748 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 | 2016-04-08 12:12:09.000 | A | 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +

ご覧のFriendshipStatusとおり、この表は時系列を構成する目的を果たしていると言えます。


関連する投稿

あなたも興味があるかもしれません:

  • この回答では、2つの異なるエンティティタイプ間の一般的な多対多の関係を処理する基本的な方法を提案します。
  • 図1に示すIDEF1Xダイアグラムは、この別の答えを示していますMarriageProgenyという名前のエンティティタイプに特に注意してください。これらは「パーツの爆発の問題」を処理する方法の2つの例であるためです。
  • この投稿は、単一の列内にさまざまな情報を保持することについての簡単な考察を示しています。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.