it-swarm.asia

Bagaimana saya harus mendesain tabel hubungan untuk pertemanan?

Jika A adalah teman dari B, maka apakah saya harus menyimpan kedua nilai AB dan BA, atau satu sudah cukup? Apa kelebihan dan kekurangan kedua metode tersebut.

Inilah pengamatan saya:

  • Jika saya menyimpan keduanya maka saya harus memperbarui keduanya ketika menerima permintaan dari seorang teman.
  • Jika saya tidak menyimpan keduanya, maka saya merasa kesulitan ketika harus melakukan beberapa JOIN dengan tabel ini.

Saat ini, saya menjaga hubungan tetap satu arah.

enter image description here

Jadi apa yang harus saya lakukan dalam kasus ini? Ada saran?

34
Chan

Saya akan menyimpan AB dan BA. Persahabatan benar-benar merupakan hubungan dua arah, setiap entitas terhubung dengan yang lain. Meskipun secara intuitif kita menganggap "persahabatan" sebagai satu tautan antara dua orang, dari sudut pandang relasional lebih seperti "A memiliki teman B" dan "B memiliki teman A". Dua hubungan, dua catatan.

30
datagod

Jika persahabatan dimaksudkan untuk menjadi simetris (yaitu tidak mungkin bagi A untuk berteman dengan B tetapi tidak sebaliknya) maka saya hanya akan menyimpan hubungan satu arah dengan batasan cek yang memastikan bahwa setiap hubungan hanya dapat diwakili satu arah.

Juga saya akan membuang id pengganti dan memiliki PK komposit sebagai gantinya (dan mungkin indeks unik komposit juga pada kolom terbalik).

CREATE TABLE Friends
  (
     UserID1 INT NOT NULL REFERENCES Users(UserID),
     UserID2 INT NOT NULL REFERENCES Users(UserID),
     CONSTRAINT CheckOneWay CHECK (UserID1 < UserID2),
     CONSTRAINT PK_Friends_UserID1_UserID2 PRIMARY KEY (UserID1, UserID2),
     CONSTRAINT UQ_Friends_UserID2_UserID1 UNIQUE (UserID2, UserID1)
  ) 

Anda tidak mengatakan pertanyaan yang menyulitkan ini tetapi Anda selalu dapat membuat Tampilan

CREATE VIEW Foo
AS
SELECT UserID1,UserID2 
FROM Friends
UNION ALL
SELECT UserID2,UserID1 
FROM Friends
13
Martin Smith

Dengan asumsi "persahabatan" selalu dua arah/saling, saya mungkin akan menanganinya seperti ini.

CREATE TABLE person (
    person_id int IDENTITY(1,1) PRIMARY KEY,
    ...other columns...
)

CREATE TABLE friendship (
    friendship_id int IDENTITY(1,1) PRIMARY KEY,
    ...other columns, if any...
)

CREATE TABLE person_friendship (
    person_id int NOT NULL,
    friendship_id int NOT NULL
    PRIMARY KEY (person_id, friendship_id)
)

Hasilnya adalah Anda mengubahnya dari banyak-ke-banyak bergabung dari "orang" menjadi "orang", ke banyak-ke-banyak bergabung dari "orang" menjadi "persahabatan". Ini akan menyederhanakan gabungan dan kendala, tetapi memiliki efek samping memungkinkan lebih dari dua orang dalam satu "persahabatan" (meskipun mungkin fleksibilitas tambahan akan menjadi keuntungan potensial).

7
db2

Anda mungkin perlu menentukan indeks di sekitar pertemanan alih-alih menggandakan jumlah baris:

CREATE TABLE person
(
    person_id INT NOT NULL AUTO_INCREMENT,
    ...
    PRIMARY KEY (person_id)
);
CREATE TABLE friendship
(
    friend_of INT NOT NULL,
    friend_to INT NOT NULL,
    PRIMARY KEY (friend_of,friend_to),
    UNIQUE KEY friend_to (friend_to,friend_of)
);

Dengan cara ini, Anda menggandakan penyimpanan untuk indeks tetapi tidak untuk data tabel. Akibatnya, ini harus menjadi penghematan 25% pada ruang disk. MySQL Query Optimizer akan memilih hanya melakukan pemindaian rentang indeks, itulah sebabnya konsep mencakup indeks berfungsi dengan baik di sini.

Berikut adalah beberapa tautan bagus di Indeks Tertutup:

CAVEAT

Jika persahabatan tidak saling menguntungkan, Anda memiliki dasar untuk jenis hubungan lain: FOLLOWER

Jika friend_to bukan teman friend_of, Anda bisa mengabaikan hubungan itu.

Jika Anda ingin mendefinisikan hubungan untuk semua jenis, apakah itu saling atau tidak, Anda mungkin bisa menggunakan tata letak tabel berikut:

CREATE TABLE person
(
    person_id INT NOT NULL AUTO_INCREMENT,
    ...
    PRIMARY KEY (person_id)
);
CREATE TABLE relationship
(
    rel_id INT NOT NULL AUTO_INCREMENT,
    person_id1 INT NOT NULL,
    person_id2 INT NOT NULL,
    reltype_id TINYINT,
    PRIMARY KEY (rel_id),
    UNIQUE KEY outer_affinity (reltype_id,person_id1,person_id2),
    UNIQUE KEY inner_affinity (reltype_id,person_id2,person_id1),
    KEY has_relationship_to (person1_id,reltype_id),
    KEY has_relationship_by (person2_id,reltype_id)
);
CREATE TABLE relation
(
    reltype_id TINYINT NOT NULL AUTO_INCREMENT,
    rel_name VARCHAR(20),
    PRIMARY KEY (reltype_id),
    UNIQUE KEY (rel_name)
);
INSERT INTO relation (relation_name) VALUES
('friend'),('follower'),('foe'),
('forgotabout'),('forsaken'),('fixed');

Dari tabel relasi, Anda dapat mengatur hubungan untuk menyertakan yang berikut:

  • Teman harus saling menguntungkan
  • Musuh bisa saling menguntungkan atau tidak
  • Pengikut bisa saling atau tidak
  • Hubungan lainnya akan tunduk pada interpretasi (oleh yang dilupakan atau ditinggalkan atau penerima balas dendam (tetap))
  • Kemungkinan hubungan bisa diperpanjang

Ini harus lebih kuat untuk semua hubungan, apakah hubungan itu timbal balik atau tidak.

4
RolandoMySQLDBA

Jika Anda dapat mengontrol dalam aplikasi bahwa id A selalu lebih rendah dari id B (pre order A, elemen B id) Anda dapat memanfaatkan bertanya tanpa OR (pilih di mana id_A = a AND id_B = b, alih-alih bertanya (id_A = a AND id_B = b) OR (id_A = b AND id_B = a)), dan juga menjaga setengah dari catatan yang Anda perlukan dengan perkiraan pihak lain. Maka Anda harus menggunakan bidang lain untuk mempertahankan keadaan hubungan (adalah-teman, a-solicited-to-b, b-solicited-to-a, exfriends-a, exfriends-b), dan Anda sudah selesai.

Ini adalah cara saya mengelola sistem pertemanan saya, dan ini menyederhanakan sistem dan menggunakan setengah baris yang Anda perlukan dengan sistem lain, hanya mengatakan A sama dengan nilai id yang lebih rendah dalam kode.

1
appartisan