首页 文章

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

提问于
浏览
1

我正在编写一个项目管理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    |
+----------+   +-------------+   +--------------+   +-------------+

我将基本关系视为:

  • 一个 user 可以有很多 projectstasksappointments .

  • 一个 project 可以有很多 userstasksappointments .

  • one task 可以有多个 users ,但只能与一个 project 相关联 . task 无法与 appointment 关联 .

  • tasks 的规则也适用于 appointments .

我的问题是:何时适合使用映射表,何时适合将数据直接包含在关联表中?我对我的例子的看法是:

  • 为每个users-projects / tasks / appts都有一个映射表,因为每种类型可以有很多用户,每个用户每种类型都有很多用户
    任务和约会表中的
  • 包含一个 project_id 字段,可用于将任务和约会与项目相关联,从而将该项目的用户关联起来 .

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

2 回答

  • 2

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

    最佳实践规定必须将数据建模为数据,而不考虑使用或应用程序 . 不考虑平台,但这些天世界是颠倒和倒退,首先选择平台 .

    建模意味着您在考虑第二个实体之前首先识别并考虑实体(例如“映射”) .

    没有选项

    我的问题是:什么时候适合使用映射表

    这是正常的方法 .

    • 正确

    • 理论上成立

    • 允许用户期望数据库具有的所有功能和能力

    • 例如 . 聚合,单个或多个项目(列表的子集)搜索非常快,等等

    • 易于扩展

    • 可防止可预防的错误

    • 为您提供可以在天堂兑现的筹码 .

    何时适合将数据直接包含在关联表中?

    决不 . 这将在单个列中创建以逗号分隔的列表 .

    • 不正确

    • 没有理论依据

    • 打破第一范式

    • 亲爱的无能(他们不仅不知道他们什么时候打破了他们所知道的一些规则)

    • 数据库功能和功能无法使用

    • 例如 . 搜索,确定特定用户是否正在处理项目将导致表扫描

    • 结果不是数据库,它是记录归档系统

    • 难以扩大

    • 你将用一半的时间来修复可预防的错误,另一半考虑如何更换它而不让任何人注意到

    • 保证你在地狱,第六级的特定地方,欺诈和欺骗 Worker 的工资,一级低于谋杀,一级高于pædophiles和战争贩子

    为每个用户 - 项目/任务/设备提供映射表,因为每种类型可以有许多用户,每个用户每种类型都有很多用户

    一般来说,是的 . 但目前尚不清楚 . “类型”响起铃声,听起来你打算有一张 table 可以支持所有可能性;可空的外键;等 . 请参阅上面的“从不” .

    只有那些需要它的表对之间应该有一个 Associative Table (不是"mapping"),而不是在每种可能性之间 . 每个这样的表只涉及一个离散对("links","maps","connects") .

    这将在标准化完成后解决,接下来......

    考虑

    这个要求听起来有点可疑 . 我不接受这些表格都是孤立的,零碎的事实 . 考虑:

    • 首先,任务可能是Project的一个孩子(你暗示过,这样的依赖应该是明确的) . 同样,约会应该是项目的孩子 . 在中,除了在项目的上下文中,任务不能存在 . 同样适用于约会 .

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

    • 如果用户与项目(而不是特定任务)相关,则根据要求,它似乎过于笼统 . 特别是如果约会应用项目,因此应用于分配给项目的所有用户 .

    • 所以我觉得到目前为止收到的信息,加上我的建议(没有确认,所以这个是薄冰),约会是在较低级别,任务级别,并可能适用于分配给任务的所有用户 .

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

    • 只要我的建议是正确的,特别是用户被分配到任务,如果在任务级别进行约会,它适用于分配给该任务的所有用户,那么没有关联(“映射”)表所有 .

    • ID无法提供行唯一性 . 如何确保行唯一性,如关系数据库所要求的那样?

    正如您所看到的,在模型的第一个草案中感知的每个表上标记ID列会阻止数据建模练习 . 你需要10到12个草稿 . 在第五个左右,您将分配密钥 . 在9或10,您将为需要它们的几个表(如果有)分配ID .

    首先分配ID可以保证RFS中的第一个草案实现,这意味着没有数据库完整性,没有数据库功能 .

    考虑,确认/凹陷,讨论等

    这是一个用作讨论平台的图表 . 请使用它底部的链接,并熟悉符号,以适合您认为合适的级别 .

    Project Management ERD • Second Draft

  • 4

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

    请使用与关系紧密匹配的单词 . 例如,我怀疑在正常的对话过程中,一个用户会问另一个用户是否有项目 . 它更像是"Are you involved in this project?"或"Are you working on this project?"因此,用户可以参与许多项目,项目可以让很多用户参与其中 . 具体说明关系是什么,但你不必得到它的肛门 . 可能有几个紧密配合 - 选择一个并继续 .

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

    你可以选择一对多的关系 . 例如,任务仅为一个项目“执行” . 这意味着FK to Project可以成为Task元组的一部分 . 但您也可以实现一对多映射表 . 这种情况通常是在这种关系似乎至少有可能在未来的某个时间发展为多对多的情况下完成的 .

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

    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可能抱怨,但用户会很感激 - 而且最终支付你工资的是用户 .

相关问题