数据库设计:使用映射表或直接在表中包含数据

Database Design: Use mapping tables or include data directly in tables

我正在编写一个项目管理 Web 应用程序,只是为了练习。基本思想是用户可以将项目添加到应用程序,然后通过界面管理与项目相关的任务和约会。我目前正在设计数据库,我想知道这里有什么最佳实践。

到目前为止我有 4 个 table:

+----------+   +-------------+   +--------------+   +-------------+
|Users     |   |Projects     |   |Tasks         |   |Appointments |
+----------+   +-------------+   +--------------+   +-------------+
|id        |   |id           |   |id            |   |id           |
|username  |   |project_name |   |task_name     |   |appt_name    |
|fname     |   |project_desc |   |task_details  |   |appt_details |
|sname     |   |             |   |task_deadline |   |appt_date    |
+----------+   +-------------+   +--------------+   +-------------+

我将基本关系视为:

我的问题是:什么时候 suitable 使用映射 tables 什么时候 suitable 直接在关联的 table 中包含数据?我对我的例子的看法是:

这是正确的方法还是有更好的解决方案?我对数据库设计还很陌生,所以我非常感谢一些建设性的批评

一个建议可能听起来不像是技术建议,更像是语法建议。在描述您的实体及其彼此之间的关系时,不要提及甚至考虑table、专栏或其他内容。在设计过程的开始,它们是实体——不是 tables,属性——不是列。不要过早地影响物理设计。

使用与关系密切匹配的词。例如,我怀疑在正常的对话过程中,一个用户会问另一个用户是否 "have a relationship" 有一个项目。它会更像 "Are you involved in this project?" 或 "Are you working on this project?" 所以一个用户可以 参与 许多项目,一个项目可以有很多用户 参与 在里面。具体说出这种关系是什么,但你不必为此大惊小怪。可能有多个匹配项 -- 选择一个并继续。

至于映射table,当你描述多对多关系时,你真的没有太多选择。

您确实可以选择一对多关系。例如,一项任务是 "performed for" 只有一个项目。这意味着到项目的 FK 可以是任务元组的一部分。但是你也可以实现一对多的映射table。当这种关系似乎至少有可能在未来的某个时候演变成多对多时,通常会这样做。

多对多和一对多映射之间的区别table是微不足道的:

create table UserProjectMap(
    int    UserID  not null,
    int    ProjectID not null,
    constraint FK_UserProject_User foreign key( UserID )
        references Users( ID ),
    constraint FK_UserProject_Project foreign key( ProjectID )
        references Projects( ID ),
    constraint PK_UserProjectMap primary key( UserID, ProjectID )
);

create table TaskProjectMap(
    int     TaskID not null,
    int     ProjectID not null,
    constraint FK_TaskProject_Task foreign key( TaskID )
        references Tasks( ID ),
    constraint FK_TaskProject_Project foreign key( ProjectID )
        references Projects( ID ),
    constraint PK_TaskProjectMap primary key( TaskID )
);

如果你错过了,这是每个定义的最后一行。

将一对多映射 table 转换为多对多很容易——只需在一侧删除唯一约束即可。或者,在上面的示例中,重新定义 PK 以包含两个 FK 字段。这意味着没有结构变化,当设计已经使用了很长时间时,结构变化是极其困难的——除非你提前做好了准备。

不过那是500级的作品。

哦,再提一个建议。不要太快去规范化或进行任何更改,除非这样做会使开发人员的查询或 DML 更容易。数据库的唯一目的(以及您作为设计者的目标)是满足用户的需求,而不是数据库开发人员。在需求列表的顶部是数据完整性。不要为了提高性能或便于维护而牺牲数据完整性。 DBA 可能会抱怨,但用户会感激 - 最终支付您薪水的是用户。

I'm currently designing the Database and I was wondering what best practice would dictate here

最佳实践规定必须将数据建模为数据,而不考虑用途或应用程序。不考虑平台也是如此,但是现在世界颠倒了wards,首先选择平台。

建模意味着您首先确定并考虑实体,然后再考虑要用它们做什么(例如 "mapping")。

没有选项

My question is: when is it suitable to use mapping tables

这是正常的方法。

  • 正确
  • 理论上成立
  • 允许用户期望数据库具有的所有功能和能力
    • 例如。聚合、单个或多个项目(列表的子集)搜索非常快等
  • 易于扩展
  • 防止table错误
  • 给你筹码,你可以在天堂兑现。

and when is it suitable to include the data directly in the associated table?

从来没有。这将在单列中创建一个逗号分隔的列表。

  • 不正确
  • 无理论依据
  • 打破第一范式
  • 无能者的宠儿(他们不仅不知道规则,而且不知道什么时候他们会违反他们 知道的几条规则)
  • 无法使用数据库特性和功能
    • 例如。搜索并确定特定用户是否正在处理项目将导致 tablescan
  • 结果不是数据库,它是一个记录归档系统
  • 难以扩展
  • 你会花一半的时间去修复预防table的错误,另一半的时间在想着如何在不让任何人注意到的情况下替换它
  • 保证你在地狱中有一个特定的地方,第六层,有欺诈和骗取工人工资的人,比谋杀低一级,比恋童癖和war贩子
  • 高一级

have a mapping table for each of users-projects/tasks/appts because there can be many users for each type and many of each type per user

一般来说,是的。但这还不清楚。 "Type"敲响了警钟,听起来你打算拥有一个支持所有可能性的table;可为空的外键;等等。参考上面的"Never"。

应该有一个关联Table(不是"mapping")只在那些需要它的table之间,而不是在它们之间每一种可能性。每个这样的 table 只与 ("links"、"maps"、"connects") 一对离散的关系相关。

这将在规范化完成后解决,接下来...

考虑

这个要求听起来有点可疑。我不接受那些 table 都是孤立的、零碎的事实。考虑:

  • 首先,Tasks 可能是 Project 的子项(您已经暗示,这种依赖关系应该是明确的)。同样,Appointments 应该是 Project 的子项。如同,任务不能存在,除非在项目的上下文中。约会也是如此。

  • 然后你必须评估用户是否应该与项目相关(如需求中给出的那样)。在我看来,一个用户被分配给一个任务(因此与项目相关,因为任务属于一个项目),而不是分配给项目中的所有任务。同样对于 User::Appointment.

  • 如果用户与项目相关(而不是特定任务),根据要求,它看起来太笼统了。特别是如果一个约会应用一个项目,并因此应用到分配给该项目的所有用户。

  • 所以在我看来,目前收到的信息,加上我的建议(尚未得到证实,所以这是薄冰),任命是在较低级别进行的,任务级别,并且可能适用于分配给该任务的所有用户。

  • 在项目级别可能有第二种约会,它适用于分配给项目中所有任务的所有用户的不同集合.

  • 只要我上面的建议是正确的,特别是用户分配给任务,如果在任务级别进行约会,它适用于分配给该任务的所有用户,那么有根本没有关联 ("mapping") Table。

  • ID 无法提供行唯一性。您如何根据关系数据库的要求确保行的唯一性?

如您所见,在模型初稿中感知到的每个 table 上标记一个 ID 列会削弱、阻止数据建模练习。你需要 10 到 12 个草稿。在第五个左右的某个地方,您将分配键。在 9 或 10,您将分配 ID 给少数需要它们的 table(如果有的话)。

分配 ID 首先保证在 RFS 中实现初稿,这意味着没有数据库完整性,没有数据库功能。

考虑、confirm/dent、讨论等

这是用作讨论平台的图表。请使用它底部的 link,并熟悉 Notation,达到您认为合适的水平。

Project Management ERD • Second Draft