为什么没有主键的表是个坏主意?

时间:2016-09-22 22:44:29

标签: sql sql-server entity-framework entity-framework-6

我对数据建模非常陌生,根据微软的实体框架,不允许没有主键的表,这显然是个坏主意。我试图找出为什么这是一个坏主意,以及如何修复我的模型,以便我没有这个洞。

我目前的模型中有4个表:User,City,HelloCity和RateCity。它的建模如图所示。这个想法是许多用户可以访问许多城市,用户只能对一个城市进行一次评级,但他们可以多次迎接一个城市。出于这个原因,我在HelloCity表中没有PK。

有关如何更改此内容以符合最佳做法的任何见解,以及为什么这会违反最佳做法?

enter image description here

4 个答案:

答案 0 :(得分:9)

此回复主要以意见/经验为基础,因此我列举一些浮现在脑海中的理由。请注意,这并非详尽无遗。

以下是您应该使用主键(PK)的一些原因:

  1. 它们允许您有一种方法来唯一地标识表中的给定行,以确保没有重复。
  2. RDBMS为您强制执行此约束,因此您无需在插入之前编写其他代码来检查重复项,从而避免进行全表扫描,这意味着此处的性能会更好。
  3. PK允许您创建外键(FK),以便以RDBMS“意识到”它们的方式在表之间创建关系。没有PKs / FK,这种关系只存在于程序员的脑海里,被引用的表可能有一行删除了它的“PK”,而另一个带有“FK”的表仍然认为存在“PK”。这很糟糕,这导致了下一点。
  4. 它允许RDBMS强制执行完整性约束。 TableA.id是否引用了TableB.table_a_id?如果TableB.table_a_id = 5,那么保证id = 5中有一行TableA。保持数据完整性和一致性,这很好。
  5. 它允许RDBMS执行更快的搜索b / c PK字段被索引,这意味着在搜索某些内容时,表不需要检查其行的所有
  6. 在我看来,拥有PK可能合法(即RDBMS会让你),但它不是道德(即你不应该这样做)。我认为你需要有非常好/有力的理由来争辩在你的数据库表中使用PK(我仍然觉得它们有争议),但是根据你目前的经验水平(即你说你是“数据建模的新手”),我说它还不足以证明缺乏PK的合理性。

    还有更多的理由,但我希望这足以让你完成它。

    就你的M:M关系而言,你需要创建关联表,你可以在其中创建一个复合PK,PK是其他两个表的2个PK的组合。

    换句话说,如果表M:MA之间存在B关系,那么我们会创建一个与C关联的表1:M同时使用表格AB。 “图形化”,它看起来类似于:

    +---+ 1  M +---+ M  1 +---+
    | A |------| C |------| B |
    +---+      +---+      +---+
    

    C表PK有点像这样:

    +-----+
    |  C  |
    +-----+
    | id  |  <-- C.id = A.id + B.id (i.e. combined/concatenated, not addition!)
    +-----+
    

答案 1 :(得分:3)

主键实质上标记了具有唯一标识符的行。这可以由一行中的一列或多列组成,但最常见的只是使用一列。使其有用的部分原因是当您有其他表(例如场景中的表)时,您可以在其他表中引用此值。由于它是唯一的,我可以在另一个表(例如HelloCity)中查看具有该唯一ID的列,并立即知道在User表中查找的位置以获取有关该列所指的人的更多信息

例如,HelloCity仅存储UserCity的ID。为什么?因为当您已将其存储在其他位置时,重新记录有关City的所有数据以及另一个表中有关User的所有数据,这是愚蠢的。它的美妙之处在于,用户需要出于某种原因更新其DisplayName。为此,您只需在User中进行更改即可。现在,引用用户的任何行都会立即返回新的DisplayName;否则你必须使用旧的DisplayName查找每条记录并相应地更新它,这在较大的数据库中可能需要相当长的时间。

请注意,主键在该特定表中仅是唯一的 - 理论上您可以在CityUser表中看到相同的主键值(如果您&#39;重新使用简单整数作为ID)但您的数据库将根据您在表之间建立的关系以及查询中的JOIN语句来了解差异。

主键帮助的另一种方式是它们自动在列上生成索引。这可以提高WHERE子句搜索主键列值的查询的性能。而且,由于您可能会在其他表中引用该主键,因此它也可以更快地进行查找。

在您的数据模型中,我看到一些列已经有了&#39; Id&#39;在他们中。在不知道您的数据集的情况下,我希望那些已经具有所有唯一值的数据,因此在这些数据库上放置PK应该没问题。如果您在执行此操作时出错,则可能存在重复。

回到关于HelloCity的问题 - 当涉及到密钥时,实体框架有点挑剔。如果你真的想要安全地玩它,你可以为每个条目自动生成一个唯一的ID,并称之为好。这是有道理的,因为它是多对多的关系,这意味着任何组合都可以出现任意次数,因此理论上没有可靠的方法来区分唯一条目。如果您希望将来删除单个条目,您如何知道要引用的行?您可以在所有字段上进行搜索并且问候语可能不同,但如果对具有相同问候语的城市进行多次访问,您可能会意外删除所有这些记录而不只是一个。

但是,如果它是一对一的关系,您可以将CityIdUserId组合成主键,因为该组合应始终是唯一的(因为您应该从来没有看到多行进行相同的组合。)

答案 2 :(得分:2)

主键的两个主要原因:

  1. 唯一标识记录以供日后参考。
  2. 准确有效地加入其他表格。

答案 3 :(得分:0)

晚了聚会,但我想补充一点,在特殊情况下,表不需要主键或任何类型的键。

例如,以 singleton 为例。始终包含单行(或行数众所周知)的表。 Oracle中的dual表就是一种情况。

通常,单例的主键为():即没有列的键。不过,我不知道任何允许它的数据库。

在其他情况下,不需要PK,通常使用通常是“端表”的日志表,因为通常将其绘制在图的边界;没有其他表格引用它们(即它们没有子代)。充分利用索引就足以应对它们,因为从本质上讲,它们不需要强制执行行唯一性。

但是,要关闭,是的,关系数据库中99.99%的表应该具有PK。

相关问题