钻石模式:那是如何(去)规范化的?
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:journalist 和 camera operator 可以看作是 person 的子类型。要携带特定于此类子类型的属性,请创建主键为person_id
的表,该表是 Person 表的外键,与 person 具有零对一的基数。例如,如果一个人是摄像机操作员,那么摄像机操作员表将具有该人的条目。这样,Person 带有公共属性,而子类型表带有特定于子类型的那些属性。以上是关于钻石模式:那是如何(去)规范化的?的主要内容,如果未能解决你的问题,请参考以下文章