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

Database 数据库设计:使用映射表或直接在表中包含数据,database,database-design,relational-database,Database,Database Design,Relational Database,我正在编写一个项目管理web应用程序,只是为了练习。其基本思想是,用户可以将项目添加到应用程序中,然后通过界面管理与项目相关的任务和约会。我目前正在设计数据库,我想知道这里的最佳实践是什么 到目前为止,我有4张桌子: +----------+ +-------------+ +--------------+ +-------------+ |Users | |Projects | |Tasks | |Appointments | +----

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

到目前为止,我有4张桌子:

+----------+   +-------------+   +--------------+   +-------------+
|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    |
+----------+   +-------------+   +--------------+   +-------------+
我认为基本关系是:

  • 一个
    用户
    可以有许多
    项目
    任务
    约会
  • 一个
    项目
    可以有许多
    用户
    任务
    约会
  • 一个
    任务
    可以有多个
    用户
    ,但只能与一个
    项目
    关联。
    任务
    不能与
    约会
    关联
  • 任务
    的规则也适用于
    约会
我的问题是:何时适合使用映射表,何时适合将数据直接包含在关联表中?我对我的例子的看法是:

  • 为每个用户项目/任务/应用创建一个映射表,因为每个类型可以有许多用户,每个用户可以有许多类型
  • 在任务和约会表中,包含一个
    project\u id
    字段,可用于将任务和约会与项目关联,从而与该项目的用户关联

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

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

一定要使用与关系密切匹配的词语。例如,我怀疑在正常的对话过程中,一个用户会问另一个用户是否与项目“有关系”。它更像是“你参与了这个项目吗?”或“你在做这个项目吗?”这样一个用户可以参与很多项目,一个项目可以有很多用户参与。具体地说出这段关系是什么,但你不必对它发号施令。可能会有几次非常适合——选择一次,然后继续

至于映射表,当您描述多对多关系时,实际上没有太多选择

在一对多的关系中,你确实可以选择。例如,一项任务仅为一个项目“执行”。这意味着FK to项目可以是任务元组的一部分。但您也可以实现一对多映射表。这通常是在关系似乎至少有可能在未来某个时候演变成多对多关系时进行的

多对多映射表和一对多映射表之间的差别很小:

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 )
);
如果你错过了,这是每个定义的最后一行

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

但这是500级的工作

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

我目前正在设计数据库,我想知道这里的最佳实践是什么

最佳实践规定,数据必须作为数据建模,而不考虑使用或应用程序。也不考虑平台,但当今世界是颠倒和倒退的,平台是首选

建模意味着在你考虑第二个对象之前,你首先要识别和考虑这些实体(如“映射”)。 别无选择 我的问题是:什么时候适合使用映射表

这是正常的方法

  • 正确的
  • 理论依据
  • 允许用户期望数据库具有的所有功能
    • 例如,聚合、单个或多个项目(列表的子集)搜索非常快,等等
  • 易于扩展
  • 防止可预防的错误
  • 给你筹码,你可以在天堂兑现
什么时候适合将数据直接包含在关联表中

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

  • 不正确
  • 没有理论依据
  • 打破第一范式
  • 无能者的宠儿(他们不仅不知道规则,他们也不知道自己什么时候违反了他们知道的少数规则)
  • 无法使用数据库功能
    • 搜索、确定某个特定用户是否正在处理某个项目将导致表扫描
  • 结果不是一个数据库,而是一个记录归档系统
  • 难以扩展
  • 你会花一半的时间来修复可预防的错误,而另一半的时间则在思考如何在不让任何人注意的情况下替换它
  • 保证你有一个明确的计划