钻石模式:那是如何(去)规范化的?

Posted

技术标签:

【中文标题】钻石模式:那是如何(去)规范化的?【英文标题】:Diamond schema: how (de)normalized is that? 【发布时间】:2012-03-14 05:24:24 【问题描述】:

假设我们有以下实体:

制作工作室 记者 相机操作员 新闻片段

在这个简单的世界里,制作工作室有很多记者和摄像师。每个记者都属于一个工作室。运营商也是如此。新闻片段由一名记者和一名操作员制作,他们都来自同一个工作室。

这是我将此模型放入关系数据库的幼稚方法:

CREATE TABLE production_studios(
  id                   SERIAL PRIMARY KEY,
  title                TEXT NOT NULL
);

CREATE TABLE journalists(
  id                   SERIAL PRIMARY KEY,
  name                 TEXT NOT NULL,
  prodution_studio_id  INTEGER NOT NULL REFERENCES production_studios
);

CREATE TABLE camera_operators(
  id                   SERIAL PRIMARY KEY,
  name                 TEXT NOT NULL,
  production_studio_id INTEGER NOT NULL REFERENCES production_studios
);

CREATE TABLE news_footages(
  id                   SERIAL PRIMARY KEY,
  description          TEXT NOT NULL,
  journalist_id        INTEGER NOT NULL REFERENCES journalists,
  camera_operator_id   INTEGER NOT NULL REFERENCES camera_operators
);

此架构形成形状精美的菱形 ERD 和一些问题。

问题在于,新闻片段可以将来自不同制作工作室的记者与摄影师联系在一起。我知道这可以通过编写相应的约束来解决,但是为了实验,我们假设我们正在做范式数据库设计的练习。

    第一个问题是关于术语的:声明这个模式是非规范化的是否正确?如果是,它打破了哪种范式?或者这种异常有什么更好的名称,比如记录间冗余、多路径关系等?

    如何更改此架构以使所描述的异常成为不可能?

当然,我非常感谢参考解决这个特定问题的论文。

【问题讨论】:

【参考方案1】:

天真的方法是让你的记者和camera_operators依赖实体,依赖于他们工作的工作室。这意味着制作工作室的外键成为其主键的一部分。然后,您的 news_footage 表有一个由 4 个组件组成的主键:

production_studio_id journalist_id camera_operator_id footage_id

还有两个外键:

journalist_id,production_studio_id,指向记者桌,然后 camera_operator,production_studio_id,指向相机操作员表

简单。

要么不。 现在你已经在你的 ER 模型中定义了这样一个概念,即摄影师或记者的存在取决于他们工作的工作室.这并不能很好地反映实际工作:在此模型中,人们无法更换雇主。

我们不要那样做。

在您的原始模型中,您将 与他们扮演的 _role(记者或摄像师)混淆了,并且您缺少一个实际上负责新闻制作的临时实体素材:[工作室特定] 制作团队。

我的 E-R 模型看起来像这样:

create table studio
(
  id int not null primary key ,
  title varchar(200) not null ,
)

create table person
(
  id int not null primary key ,
  title varchar(200) not null ,
)

create table team
(
  studio_id          int not null ,
  journalist_id      int not null ,
  camera_operator_id int not null ,

  primary key ( studio_id , journalist_id , camera_operator ) ,

  foreign key ( studio_id          ) references studio ( id ) ,
  foreign key ( journalist_id      ) references person ( id ) ,
  foreign key ( camera_operator_id ) references person ( id ) ,

)

create table footage
(
  studio_id          int not null ,
  journalist_id      int not null ,
  camera_operator_id int not null ,
  id                 int not null ,
  description        varchar(200) not null ,

  primary key ( studio_id , journalist_id , camera_operator_id , id ) ,

  foreign key     ( studio_id , journalist_id , camera_operator_id )
  references team ( studio_id , journalist_id , camera_operator_id ) ,

)

现在您拥有一个人们可以在其中扮演不同角色的世界:同一个人在某些情况下可能是摄像师,而在其他情况下可能是记者。人们可以更换雇主。工作室特定团队由一名记者和一名摄像师组成。在某些情况下,同一个人可能在团队中同时扮演两个角色。最后,一段新闻片段由一个且只有一个工作室特定团队制作。

这更好地反映了现实世界,并且更加灵活。

编辑添加示例查询:

要找到为特定工作室工作的记者:

select p.*
from studio s
join team   t on t.studio_id = s.id
join person p on p.id        = t.journalist_id
where s.title = 'my desired studio name'

这将为您提供一组现在(或曾经)与工作室相关联的记者角色。不过应该注意的是,在现实世界中,人们为雇主工作了一段时间:要正确建模,您需要一个开始/结束日期,并且您需要使用现在的相对概念来限定查询。

【讨论】:

你的观点很完美。事实上,我已经错过了一个人和他/她的角色。 你的观点很完美,谢谢。事实上,我已经错过了人和他/她的角色。但是现在,记者进入工作室的唯一途径是与运营商组成一个团队。假设记者(和操作员)受雇于工作室(在我的示例中由 FK 表示)。鉴于这种新模式,我如何找到特定工作室雇用的记者? @SergeBalyuk:查看我修改后的答案。 这种方法的一个问题 - 由于记者和摄像操作员表的丢失,您会丢失特定于这些角色的列的位置(例如,您不希望出现的摄像操作员的设备培训信息)人)。 @Reinderien:journalistcamera operator 可以看作是 person 的子类型。要携带特定于此类子类型的属性,请创建主键为 person_id 的表,该表是 Person 表的外键,与 person 具有零对一的基数。例如,如果一个人是摄像机操作员,那么摄像机操作员表将具有该人的条目。这样,Person 带有公共属性,而子类型表带有特定于子类型的那些属性。

以上是关于钻石模式:那是如何(去)规范化的?的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL线段光栅化规范

如何使用 pandas groupby() 的 split-apply-combine 模式同时规范化多个列

设计模式连环炮-要做规范化产品线的老厂长!

严格模式与混杂模式

文本文件规范化和模式匹配

如何将关系模式分解到BCNF(3NF)