数据库模式 - 多对多规范化

时间:2017-10-12 10:57:14

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

我正在设计一个模式,其中案例可以附加许多表单,并且表单可以用于许多情况。 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
);

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

1 个答案:

答案 0 :(得分:0)

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

  1. CaseForm上的聚簇索引扫描
  2. 在CaseForm.Incomplete上创建一个非聚集索引,其中包括CaseID,FormID和扫描
  3. 如果你没有拆分表,你的两个主要选项是:

    1. CaseFormAttribute上的聚簇索引扫描
    2. 在CaseFormAttribute.Incomplete上创建一个非聚集索引,其中包括CaseID,FormID和扫描
    3. 出于本示例的目的,查询选项1和2在性能方面大致相同。引入非聚集索引会以多种方式增加开销。它比集群索引更简化(在这个特定的例子中可能需要更多的读取扫描),它是CaseForm将占用的额外存储空间,并且必须维护索引以更新表。选项4也将执行类似的操作,与选项2具有相同的警告。选项3将是您表现最差的,因为聚簇索引扫描将包括读取您的值字段中的所有BLOB数据,即使它只需要不完整的位确定是否返回该(案例,表格)对。

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

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