塑造相互友谊

2021-07-22 21:33:21

这个子堆栈是关于什么的?以下是前 25 期的最佳创意列表。一些社交网络有一个友谊的概念,根据定义,这是相互的。你可以向某人发送“好友请求”,如果他们接受,那么你们两个就成为“好友”。 (有一个单独的追随者概念,它可能是单向的:你可以是我的追随者,但我可能是也可能不是你的追随者;这是微不足道的模型。)我今天想讨论一种共同的友谊,因为它构成几个有趣的问题。首先,让我们从要求开始。我们有以下典型的操作和查询: 我们可以将相互的友谊表示为一对有向友谊:Alice 是 Bob 的朋友,Bob 是 Alice 的朋友。我们可以设计如下物理表: CREATE TABLE Friendship ( user1_id INTEGER NOT NULL, user2_id INTEGER NOT NULL, PRIMARY KEY (user1_id, user2_id)); DELETE FROM FriendshipWHERE (user1_id = 3 AND user2_id = 5) OR (user1_id = 5 AND user2_id = 3);

我们再看一下 Alice 和 Bob 的好友关系登记表的内容: 好吧,好吧,但是这不是(不寒而栗)数据重复吗?我们的代码保证每一行都有一个对应的对称行;我们可能认为第二行是多余的。那么让我们研究一下单行设计。创建表相互友谊(user1_id INTEGER NOT NULL,user2_id INTEGER NOT NULL,PRIMARY KEY(user1_id,user2_id));我们希望每一个相互的友谊都有一行。那么,会是:?选择随机顺序不是一个好主意,因为这两种可能性最终都有可能被插入,这意味着什么?它将如何影响我们的典型查询?我们可以决定我们总是在 user1_id 中插入一个较小的 ID,在 user2_id 中插入较大的 ID。甚至可以通过在我们的表上定义 CHECK 约束来在数据库级别强制执行此操作: CREATE TABLE 相互友谊 ( user1_id INTEGER NOT NULL, user2_id INTEGER NOT NULL, PRIMARY KEY (user1_id, user2_id), CONSTRAINT user1_user2_ids CHECK (user1_id) < user2_id) ;

(但当然,如果您可以以其他方式保证代码中的这种不变性,则这不是必需的)。如果我们的不变量得到保证,我们可以通过以下查询获得 Alice 的朋友列表: 这个查询的第一个版本有问题,因为我不小心使用了看起来很明显的条件“WHERE user1_id = 5 OR user2_id = 5”。这个条件是错误的。顺便说一句,从实用的角度来看,为了提高这个查询的性能,我们还应该创建第二个表索引。第一个由主键约束提供。第二个将是“INDEX (user2_id, user1_id)”。此索引也将提高以下查询的性能。要确定 Alice 和 Bob 是否是朋友,我们将使用以下查询: 为了使此查询起作用,我们的代码必须确保第一个 ID 小于第二个 ID。因此,如果我们有某种函数可以接受两个任意 ID,则该函数需要对两个 ID 进行排序并以正确的顺序传递它们。如果我们不想或不能对代码中的 ID 进行排序,我们必须考虑 SQL 中的两个选项:

SELECT 1FROM Mutual_friendshipWHERE (user1_id = $ID1 AND user2_id = $ID2) OR (user1_id = $ID2 AND user2_id = $ID1) 这只适用于我们可以在我们的代码中预处理一对 ID 从而保证第一个 ID 是比第二个小。否则,我们必须明确地写出 OR 条件。我们在这里看到,对于这两种模型,我们都需要实现保持不变的函数来建立和删除友谊。然后我们必须确保只能通过这些函数更改数据。至于查询:如果您需要,两行模型对于临时手动和分析查询似乎要简单得多(这是一件好事)。单行模型很快就会变得乏味,或者再次需要预处理。防止数据重复是人们在谈论数据库规范化时谈论的主要内容之一。如果您要与某人讨论在两种表示之间进行选择,那么肯定会出现这个问题,我们必须确定两行模型表示是否可以接受。我们可以通过维基百科的一个例子来说明数据重复的想法。假设我们有一个具有以下结构的锦标赛获胜者表: 这种结构不是第三范式:如果同一个人赢得了多次锦标赛,我们将多次存储他们的 DOB。这就是数据重复和不一致的根源:如果我们不小心为同一个人输入了两个不同的出生日期怎么办?

为了规范这个模式,我们需要为运动员创建一个单独的表,具有以下结构:然后从锦标赛获胜者表中删除“获胜者出生日期”。这里发生了什么?现在,由于消除了数据重复,当需要更改单个数据时,将导致更改单个表值。如果我们发现其中一名运动员的出生日期不正确,我们只需要更改一个值。在非 3NF 形式中,这将需要更改无限数量的行,与他们赢得锦标赛的次数一样多。这里的关键字似乎是“无限”,它允许我们提出两行模型中没有(坏)数据重复。当我们添加或删除单个好友时,我们需要添加或删除固定数量的行,即两行。它不是无限的。我不确定这是否是每个人都可以接受的论点,我什至不确定最初的问题是否有效。坦率地说,这两种模型都感觉有些奇怪,它们强烈反对关系数据库建模的通常轻松性。也许这是因为表结构不直接处理的附加不变量?坦率地说,我有点期待有人会为这个问题提出一个更优雅的解决方案,我们都会学到新的东西。我们将在以后的帖子中调查其他一些类似的案例。我们希望找到描述这种情况的正确方法。

PS:如果您是这个子堆栈的新手,请查看前 25 期的最佳创意列表。