数据库设计:捕获用户/朋友关系的最佳表结构?

Zac*_*tes 34 database-design social-networking

我正在尝试设计一个数据模型,表示一个用户是另一个用户的朋友.这是我到目前为止所提出的,但它似乎很笨重,有更好的解决方案吗?

User
=====
Id
Name
etc...

UserFriend
===========
UserId
FriendId
IsMutual
IsBlocked
Run Code Online (Sandbox Code Playgroud)

cha*_*aos 56

UserRelationship
====
RelatingUserID
RelatedUserID
Type[friend, block, etc]
Run Code Online (Sandbox Code Playgroud)

同意共同不属于专栏; 打破正常化.

  • 九年后我来到这里,您能解释一下“打破正常化”是什么意思吗? (3认同)
  • @MohammedNoureldin:请参阅https://en.wikipedia.org/wiki/Database_normalization。使用多个冗余行跟踪相同的关系可能会让我们面临标准化所要防止的所有类型的异常。 (2认同)

Art*_*kov 37

要为每两个用户创建一条记录并避免消耗建议方法所建议的额外内存(因为每个用户有两条记录,所以需要两倍的内存),您可以执行以下操作:

  1. 表结构:

    USER_RELATIONSHIP {
        user_first_id,
        user_second_id,
        type
    
        primary key(user_first_id, user_second_id)
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 确保: user_first_id < user_second_id

  3. 最有趣的部分 - type:对于关系的所有可能状态,您可以创建相应的值.例如:

    pending_first_second
    pending_second_first
    friends
    block_first_second
    block_second_first
    block_both
    
    Run Code Online (Sandbox Code Playgroud)

你有什么:

  1. user_first_id < user_second_id确保了仅存在一个给定的两个用户之间的关系的记录,因为这和主键约束不会允许将其放置否则.
  2. 通过在关系状态之间进行适当切换,可以确定两个用户中的每个用户之间的关系.如果两个用户之间没有关系,则没有记录.
  3. 要找出两个用户之间的关系(以及更新),您只需通过一个查询:

    select * from USER_RELATIONSHIP where
        user_first_id = user1_id and
        user_second_id = user2_id;
    
    Run Code Online (Sandbox Code Playgroud)

    没有一个or声明会检查这个列反之亦然,这更快.

示例场景:

  1. no record :没有关系

  2. pending_first_second :第一个向第二个朋友提出请求

  3. friends :第二个批准了朋友请求

  4. no record :其中一个用户从他的朋友那里删除了另一个

此解决方案在内存和速度方面都很有效,因为您只创建,存储和更新一条记录.

  • 这是一个很棒的解决方案,关于我能看到的唯一问题是是否需要分片。关系表增长很快,通常需要分片。因此,如果每个关系行两行,则可以在第一个user_id上共享,并且在查询单个用户的所有朋友时,可以确保只需要检查一个分片。而如果该用户在某列中涉及某些关系,而在另一列中则涉及其他关系,则您可能必须检查所有分片。 (2认同)

kei*_*en7 9

我目前正在为客户建立一个社交网站,我这样表达了一些观点

CREATE TABLE [dbo].[PersonFriend] (
    [Id]                          INT            IDENTITY (1, 1) NOT NULL,
    [Timestamp]                   DATETIME       NOT NULL,
    [ChangeUser]                  NVARCHAR (200) NOT NULL,
    [FriendStatusId]              TINYINT        NOT NULL,
    [Person1Id]                   INT            NOT NULL,
    [Person2Id]                   INT            NOT NULL,
    [Person1RequestTimestamp]     DATETIME       NOT NULL,
    [Person2AcknowledgeTimestamp] DATETIME       NULL
);
Run Code Online (Sandbox Code Playgroud)

每个人都存储在Person表中(想象一下).Person1Id和Person2Id字段是人员表的FK.我在FriendStatus表中保留了一个状态列表,用于覆盖是否已经请求,接受,拒绝,忽略等.Timestamp字段在我的设计中是标准的,用于表示记录创建(它是由基础持久化类使用的模式事物由于Person1RequestTimestamp包含相同的数据,因此它在此表中的重复类型.当Person2看到请求并在其上发出一个动作(在FriendStatusId中显示)并将其存储在Person2AcknowledgeTimestamp中时,我也会捕获.

这种设计的核心假设之一可以说是Person1要求Person2的友谊 - 如果这种友谊被接受,那么友谊被认为是相互的.


Jef*_*rey 5

我会做类似于你所拥有的东西,但删除"IsMutual"标志.当它是相互的时,只需添加具有反向值的第二行.它确实添加了行,但感觉更清洁.