【问题标题】:Database Schema - Many-to-Many Normalisation数据库模式 - 多对多规范化
【发布时间】:2018-03-24 06:55:45
【问题描述】:

我正在设计一个模式,其中一个案例可以附加许多表单,并且一个表单可以用于许多案例。 Form 表基本上包含在客户端呈现的 html 表单的结构。提交表单时,字段的名称/值对将单独存储。如下将名称/值属性与连接表分开是否有任何价值?

CREATE TABLE Case (
   ID int NOT NULL PRIMARY KEY,
   ...
); 

CREATE TABLE CaseForm (
   CaseID int NOT NULL FOREIGN KEY REFERENCES Case (ID),
   FormID int NOT NULL FOREIGN KEY REFERENCES Form (ID),
   CONSTRAINT PK_CaseForm PRIMARY KEY (CaseID, FormID)
); 

CREATE TABLE CaseFormAttribute (
   ID int NOT NULL PRIMARY KEY,
   CaseID int NOT NULL FOREIGN KEY REFERENCES CaseForm (CaseID),
   FormID int NOT NULL FOREIGN KEY REFERENCES CaseForm (FormID),
   Name varchar(255) NOT NULL,
   Value varchar(max)
); 

CREATE TABLE Form (
   ID int NOT NULL PRIMARY KEY,
   FieldsJson varchar (max) NOT NULL
);  

我使架构过于复杂,因为可以通过将CaseFormAttribute 表转换为连接表并完全摆脱CaseForm 表来实现相同的多对多关系,如下所示?

CREATE TABLE CaseFormAttribute (
   ID int NOT NULL PRIMARY KEY,
   CaseID int NOT NULL FOREIGN KEY REFERENCES Case (ID),
   FormID int NOT NULL FOREIGN KEY REFERENCES Form (ID),
   Name varchar(255) NOT NULL,
   Value varchar(max) NULL
);

基本上我想问的是哪个设计更好?

【问题讨论】:

  • 它们都可以工作,但这取决于您需要什么表。你的 ERD 是什么样的?
  • 两者相比有什么好处或价值吗?
  • 这取决于您是否需要caseform表,但我无法发表评论,因为我不知道您的数据库设计或要求

标签: sql sql-server database-design many-to-many database-schema


【解决方案1】:

将两者分开的主要好处取决于是否将其他字段添加到 CaseForm 表中。例如,假设您想记录表单是否不完整。您可以为此添加一个不完整的位域。现在,您有两个主要选项可用于检索该信息:

  1. CaseForm 上的聚集索引扫描
  2. 在 CaseForm.Incomplete 上创建一个非聚集索引,其中包括 CaseID、FormID,并对其进行扫描

如果您没有拆分表格,您的两个主要选择是:

  1. CaseFormAttribute 上的聚集索引扫描
  2. 在 CaseFormAttribute.Incomplete 上创建一个非聚集索引,其中包括 CaseID、FormID,并对其进行扫描

就本示例而言,查询选项 1 和 2 在性能方面大致相同。引入非聚集索引会以多种方式增加开销。它比聚集索引更精简(在这个特定示例中扫描可能需要更多读取),它是 CaseForm 将占用的额外存储空间,并且必须维护索引以更新表。选项 4 也将执行类似的操作,但注意事项与选项 2 相同。选项 3 将是您表现最差的,因为聚集索引扫描将包括读取值字段中的所有 BLOB 数据,即使它只需要不完整的位确定是否返回该 (Case, Form) 对。

所以这确实取决于你未来的发展方向。

此外,如果您坚持拆分方法,请考虑将 CaseFormAttribute.ID 转换为 CaseForm,然后使用 CaseForm.ID 作为您在 CaseFormAttribute 中的 PK/FK。这里需要注意的是,我们假设所有表单都将同时插入给定案例。如果这不是真的,那么您会邀请一些页面拆分,因为您的插入会有些随机,但通常仍会增加。

【讨论】:

  • 要求是一个案例可以附加多个表单,但不能是同一个表单。它需要是多对多的关系。那么我是否需要使用三列(CaseId、FormId、Name)创建复合键?
  • @adam78 我现在看到了 - 感谢您指出这一点。我已经相应地编辑了我的答案。您的密钥是正确的,您不应在密钥中包含名称。
  • 不,我认为你是对的 - 在我的解决方案 2 中,我最终会得到重复的表单,因此我需要在该实例中添加一个唯一键(CaseId、FormId、Name)。
  • @adam78 我明白你在说什么。在解决方案 2 中,是的,您需要添加一个唯一键(假设您没有完全删除 ID 字段),但您仍然可以将 Name 排除在外。
猜你喜欢
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
  • 2013-01-22
  • 2012-03-06
  • 1970-01-01
  • 2017-09-20
相关资源
最近更新 更多