10

我和我的朋友正在建立一个网站,但存在重大分歧。该网站的核心是一个关于“人”的评论数据库。基本上人们可以输入评论,他们可以输入评论的人。然后,查看者可以在数据库中搜索评论中的单词或人名的一部分。它完全是用户生成的。例如,如果有人想对拼写错误的人名发表评论,他们可以,这没关系。所以可能有不同人的多种拼写被列为几个不同的条目(一些带有中间名,一些带有昵称,一些拼写错误等),但这一切都可以。我们不在乎人们是否对随机的人或虚构的人发表评论。

无论如何,问题在于我们如何构建数据库。现在它只是一个以评论 ID 作为主键的表,然后有一个字段用于评论的“人”:

评论 ID - 评论 - 人

1 - “他很奇怪” - 约翰史密斯

2 - “臭女孩” - 珍妮

3 - “同性恋” - 约翰史密斯

4 - “欠我 20 美元” - Jennyyyyyyyyy

一切正常。使用数据库,我能够创建列出特定“人”的所有“评论”的页面。然而,他对数据库没有规范化很着迷。我阅读了规范化并得知他错了。该表目前已规范化,因为评论 ID 是唯一的,并且规定了“评论”和“人”。现在他坚持“人”应该拥有它的 OWN 表,因为它是一个“事物”。我认为没有必要,因为即使“人”确实是更大的容器(一个“人”可以有很多关于他们的“评论”),数据库似乎运行得很好,“人”是评论 ID。我对不同的 SQL 选择使用各种 PHP 调用,以使其在输出和用户搜索和查看结果的不同方式上神奇地显得更加复杂,但实际上,设置非常简单。我现在让用户用竖起大拇指和不喜欢的方式对评论进行排名,并且我在同一张桌子上保留一个“分数”作为另一个字段。

我觉得目前没有必要为唯一的“人”条目设置单独的表格,因为“人”没有自己的“分数”或任何自己的属性。只有评论可以。我的朋友是如此坚持,以至于它是提高效率的必要条件。最后我说,“好吧,如果你要我创建一个单独的表,让'person'作为它自己的字段,那么第二个字段会是什么?因为如果一个表只有一个列,这似乎没有意义。我同意我们可能会在以后创建一个需要给“人”它自己的桌子,但我们可以处理那个。” 然后他说字符串不能是主键,我们将当前表中的“人”转换为数字,数字将成为新“人”表中的主键。对我来说,这似乎没有必要,它会使当前表格更难阅读。他还认为以后创建第二个表是不可能的,我们现在需要预测我们以后可能需要它来做一些事情。

谁是对的?

4

11 回答 11

9

在我看来,你的朋友是对的。

人应该住在不同的桌子上,你应该尝试规范化。不过,不要过度。

从长远来看,您可能希望对您的网站做更多的事情,比如说您想将多个文件附加到一个人(即图片),那么您会非常感谢标准化。

于 2010-09-10T15:18:57.050 回答
8

为 person 创建一个新表并使用该表的键代替 person 属性与规范化无关。出于其他原因,这可能是一个好主意,但这样做并不会使数据库“更规范化”而不是不这样做。所以你是对的:就规范化而言,创建另一个表是不必要的。

于 2010-09-10T17:27:38.030 回答
3

我会投票给你的朋友。我喜欢规范化并为未来做计划,即使你从不需要它,这种规范化也很容易做到,实际上不需要时间。您可以创建一个您查询的视图,以使您的 SQL 更清晰,并消除您自己连接表的需要。

于 2010-09-10T15:19:31.683 回答
2

你是对的。

Person可能是一般的事情,但不在你的模型中。如果您要让人们正确识别他们正在谈论的人,则需要一张Person表格。例如,如果评论只是关于已经在数据库中注册的人。

但在这里看起来你有一个非结构化数据,没有身份;并且没有人/没有人有兴趣确定“jenny”和“jennyyy”是否实际上是同一个人,更不用说“jenny doe”和“my cousin”了......

于 2010-09-10T15:29:52.930 回答
2

如果您已经达到了所有能力并且没有扩展能力的计划,我认为您可以保持原样。

如果您打算添加更多内容,即允许人们拥有帐户或其他任何东西,我认为将您的数据分成 Person、Comments 表可能是明智之举。它并不难,并且可以更轻松地扩展您的功能。

于 2010-09-10T15:19:45.747 回答
1

嗯,有两种思想流派。有人说,尽可能以最规范化的方式创建数据模型,然后在需要更高效率时反规范化。另一个基本上是“做这项工作所需的最少工作,然后随着你的需求变化而改变它”。也称为 YAGNI(您将不需要它)。

这完全取决于您看到的情况。如果这就是全部,那么您的方法可能很好。如果您打算随着时间的推移使用新功能对其进行改进,那么您的朋友是对的。

于 2010-09-10T15:24:42.367 回答
1

如果您从不打算将人员列与用户或其他任何内容相关联,并且数据显然不需要一致性或数据完整性检查,那么为什么要在关系数据库中这样做呢?这不是 nosql 数据库的用例吗?还是我错过了什么?

于 2010-09-10T20:45:52.410 回答
1

规范化是关于功能依赖(FD)的。您需要识别数据模型属性中存在的所有FD,然后才能对其进行完全规范化。

让我们回顾一下你所拥有的:

  • a 的任何给定实例在CommentId功能上确定Person (FD: CommentId-> Person)
  • a 的任何给定实例在CommentId功能上确定Comment(FD: CommentId-> Comment)
  • a 的任何给定实例在CommentId功能上确定UserId(FD: CommentId-> UserId)
  • a 的任何给定实例在CommentId功能上确定Score(FD: CommentId-> Score)

CommentId这里的 一切都是独立的依赖属性CommentId。这可能会导致您相信包含上述所有属性或其中一部分属性的关系(表)必须被规范化。

首先要问自己的是,你为什么要创建这个CommentId属性?严格来说,这是一种人造属性——它与任何“真实”无关。CommentId 通常被称为代理键。代理键只是一个组成的值,代表与其他一些属性组相对应的唯一值集。那么哪些属性组是CommentId 代理项呢?我们可以通过询问以下问题并向模型添加新的 FD 来解决这个问题:

  • 1)评论必须是唯一的吗?如果是这样,FD: Comment->CommentId必须为真。
  • 2) 只要​​是关于不同的人,可以多次发表相同的评论吗?如果是,那么 FD: Person+ Comment->CommentId必须为真,上面 1 中的 FD 为假。
  • 3) 如果同一评论是由不同的 UserId 发表的,是否可以对同一个人多次发表相同的评论?如果是这样,则 1 和 2 中的 FD 不能为真,但 FD: Person++ ->Comment可能为真。UserIdCommentId
  • 4) 同一个 UserId 是否可以对同一个人多次发表相同的评论,但分数不同?这意味着 FD: Person++ ' + Comment- >为真,其他为假。UserIdScoreCommentId

以上 4 个 FD 中的一个必须为真。无论哪种方式都会影响您的数据模型的规范化方式。

假设 FD: Person+ Comment+ UserId->CommentId证明是真的。合乎逻辑的后果是:

  • Person++Comment并作为等效UserIdCommentIdScore
  • Score应该与它的一个但不是两个键建立关系(以避免传递依赖)。显而易见的选择是,CommentId因为它是专门作为代理创建的。
  • 需要一个由以下组成的关系:CommentId, Person, Comment,UserId将 Key 与其代理项联系起来。

从理论的角度来看,代理键CommentId不是使您的数据模型或数据库工作所必需的。但是,它的存在可能会影响关系的构建方式。

代理键的创建是一个具有一定重要性的实际问题。考虑如果您选择不使用代理键而是使用完整的属性集Person++Comment代替它可能会发生什么UserId,特别是如果多个表需要它作为外键或主键:

  • 注释可能会为您的数据库增加大量空间开销,因为它在多个表中重复出现。它的长度可能超过几个字符。
  • 如果有人选择编辑评论会发生什么?该更改需要传播到 Comment 是键的一部分的所有表。不是一个漂亮的景象!
  • 索引长的复杂键可能会占用大量空间和/或降低更新性能

分配给代理键的值永远不会改变,无论您对与它确定的属性关联的值做什么。更新依赖属性现在仅限于定义代理键的一个表。这具有巨大的现实意义。

现在回到您是否应该为Person. 是否Person生活在许多或任何 FD 的左侧?如果是这样,它的值将通过您的数据库传播,并且有必要为它创建一个代理项。Person 是文本属性还是数字属性与创建代理键的选择无关。

根据您所说的,为Person. 这个论点是基于这样的怀疑,即它的值可能会在未来的某个时刻成为密钥或密钥的一部分。

于 2010-09-10T20:38:08.173 回答
0

有了这个数据库,你可能觉得还可以,但是以后想让用户从数据库中了解更多的时候,可能会出现一些问题。假设你想知道一个人的评论数= 'abc'。在这种情况下,您将必须遍历整个评论表并继续计数。代替此,您可以为每个人设置一个名为“count”的属性,并在对其进行评论时将其递增人。
就规范化而言,拥有规范化的数据库总是更好,因为它减少了冗余并使数据库直观易懂。如果您预计您的数据库将来会变大,那么规范化必须存在。

于 2014-03-17T13:58:52.903 回答
0

这是交易。每当您创建某些东西时,您都希望确保它有成长的空间。您想尝试为您的计划预测未来的项目和未来的进步。在这种情况下,您说得对,目前不需要添加仅包含 1 个字段的人员表(不计算 ID,假设您有一个 int ID 字段和一个人名)。但是,在将来,您可能希望为此类人提供其他属性,例如名字、姓氏、电子邮件地址、添加日期等。

虽然过度规范化肯定是有害的,但我个人会创建另一个更大的表来容纳具有附加字段的人,以便我将来可以轻松添加新功能。

于 2010-09-10T15:20:12.507 回答
0

每当您与用户打交道时,都应该有一个专用表。然后您可以加入这些表并引用该用户的 ID。

user -> id | username | password | email

comment -> id | user_id | content

将评论加入用户的 SQL:

SELECT user.username, comment.content FROM user JOIN comment WHERE user.id = comment.user_id;

将来当您想要查找有关该特定用户的信息时,它将变得更加容易。额外的努力可以忽略不计。

关于每条评论的“分数”,这也应该是一个单独的表格。这样,您可以将用户与“喜欢”或“不喜欢”联系起来。

于 2013-12-17T20:07:49.207 回答