2

ユーザ間の関係データを保持するMySQLテーブルを作成します。ユーザーAとユーザーBとユーザーBとユーザーAとの関係は異なる場合があります。同じFOREIGN KEY IDを使用する2つのユニークキーでのMySQL CONSTRAINT

例:ボブ(から)アリス(へ)の

  1. 関係:0.9 - ボブはアリスのものを愛しています。
  2. アリスから(から)ボブへの関係:0.5 - アリスはボブのものを普通ではないと判断します。

私の質問:私は、ユーザーテーブルにuser_idsを参照する2つの外部キーにUNIQUEキーとして2つの制約を実装している

。これはできますか?それらは2つの別個の一意のキーとして扱われますか?

user_idごとにUserA(から)UserB関係とUserB(から)UserA関係のそれぞれの出現を1つだけ許可するCONSTRAINTを実装するにはどうすればよいですか?私は正しい方法でそれについて行くのですか?

SQL:

CREATE TABLE relationships (
    relationship_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, 
    from_user_id MEDIUMINT UNSIGNED NOT NULL, 
    to_user_id MEDIUMINT UNSIGNED NOT NULL, 
    relationship_level DECIMAL(1,1) NOT NULL, 
    PRIMARY KEY (relationship_id), 

    FOREIGN KEY (from_user_id) REFERENCES users (user_id) 
    ON DELETE CASCADE ON UPDATE NO ACTION, 

    FOREIGN KEY (to_user_id) REFERENCES users (user_id) 
    ON DELETE CASCADE ON UPDATE NO ACTION, 

    CONSTRAINT from_to_relationship UNIQUE KEY (from_user_id, to_user_id), 
    CONSTRAINT to_from_relationship UNIQUE KEY (to_user_id, from_user_id), 

    INDEX relationship_from_to (relationship_id, from_user_id, to_user_id, relationship_level), 
    INDEX relationship_to_from (relationship_id, to_user_id, from_user_id, relationship_level) 

) ENGINE=INNODB; 

私は、誰かが助けることができると思います。

答えて

2

UNIQUEのうちの1つだけを保持してください。両方を持つ必要はありません。行が失敗した場合、UNIQUE KEY (from_user_id, to_user_id)も失敗し、UNIQUE KEY (to_user_id, from_user_id)になります。その逆も同様です。ただ1つのUNIQUE制約があっても、アリスとボブの間の関係を表現しようとするときには、最大1つの{アリス、ボブ}行、を最大1つの{ボブ、アリス}行にできます。

パフォーマンス(つまり両方向の関係をトラバースする)に関しては、{from_user_id, to_user_id}(「前方」トラバーサルの場合)または{to_user_id, from_user_id}(「後方」トラバーサルの場合)のインデックスを検討するとよいでしょう。代理プライマリキー(relationship_id)を捨てて、自然なPKを探し出し、インデックス作成の必要性を減らすこともできます(セカンダリインデックスはクラスタ化テーブルでは高価です。Understanding InnoDB clustered indexes、「クラスタリングの短所」を参照)。私の意見で

、あなたのテーブルには、次のようになります。

CREATE TABLE relationships (
    from_user_id MEDIUMINT UNSIGNED NOT NULL, 
    to_user_id MEDIUMINT UNSIGNED NOT NULL, 
    relationship_level DECIMAL(1,1) NOT NULL, 
    PRIMARY KEY (from_user_id, to_user_id), -- InnoDB is clustered, so naturally "covers" relationship_level as well. 
    FOREIGN KEY (from_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION, 
    FOREIGN KEY (to_user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION, 
    INDEX relationship_to_from (to_user_id, from_user_id, relationship_level) -- Including relationship_level may or may not be a good idea. 
) ENGINE=INNODB; 

注:あなたはINDEXでrelationship_levelを含めるかどうか、あなたが「後方」方向にindex-only scan同様にしたいかどうかに依存するかどうか。 「forward」の方向は当然(InnoDBがclusteredであるため)PKによってカバーされます。

+0

これは多くのありがとう、いくつかをクリアしました。しかし、PK(from_user_id、to_user_id)に関しては、 "InnoDBはクラスタ化されているので、当然" "relationship_level"もカバーしています。これは、実際にINNODBテーブルがインデックスのリーフページに行を格納する方法によって、このPKから直接特定のrelationship_levelにアクセスできることを意味しますか? – leokennedy

+0

@KennedyLはい。基本的には、テーブル全体がインデックス内に格納されています(「ヒープ」は一切ありません)。したがって、PRIMARY KEYに明示的に記載されているフィールドだけでなく、すべてのテーブルのフィールドをカバーします。論理的な観点から問合せを扱うことは問題ではありませんが、パフォーマンスに関しては重要です(理由を理解するために提供している「索引のみのスキャン」に関するIndex Lukeリンクを参照してください)。 –

+0

完璧、多くのおかげでBranko。私はリンクされた記事を徹底的に読むでしょう。 – leokennedy

関連する問題