我想知道如何在 Relation 中正确设置主键。例如。我们有 ER-diagram ,其中包含元素:
为了将其转换为关系模型,我们应该做一些技巧。上面的所有元素都涉及关系的主键,但它们都是自然键 - 因此我们可以将它们保留为或替换为代理键。
考虑一些情况。
密钥属性是一个名称 - 因此它必须是CHAR
或VARCHAR
类型。通常名称变为关键属性。
两个(或更多)识别关系成为关系的复合主键(由外键组成)。
使用弱键属性识别关系 也会成为复合主键。
关联实体通常有两个或更多识别关系,因此它们应该是连接关系(连接表)。
如何为 Relations 设置主键以处理上述所有情况(可能还有一些我未提及的案例)?
如何避免使用代理键以及必要的情况?
如何设置主键的数据类型?
如果必须将复合主键传递给子关系,是否应该用代理替换?
在我的视图中使用代理键的优点和缺点:
它们紧凑(通常为INT
类型),有时可以替代复合键
他们在外键
他们无痛地编入索引
他们的数字和毫无意义。例如。我希望在我的界面应用程序中填写 Junction Table - 所以除了只涉及数字之外我别无选择
他们是多余的
他们感到困惑
至于设置数据类型 - 必须有更多技巧以及整体设置主键。
我本来应该给出一个例子,但我没有。所以这是一个例子。 考虑我们有两个相互作用的主要实体(仍然不知道如何在这里说明图表这样的东西 - 所以我将它们显示为用来演示国际空间站工作人员轮换系统的表格):
SpaceShip
╔════════════════╤════════════════╗
║ ShipName │ ShipType ║ ShipName - Primary Key
╟────────────────┼────────────────╢ ShipType - Foreign Key (but it is
║ Soyuz TMA-14 │ Soyuz ║ not being considered here)
║ Endeavour │ Space Shuttle ║
║ Soyuz TMA-15M │ Soyuz ║
║ Atlantis │ Space Shuttle ║
║ Soyuz TM-31 │ Soyuz ║
║ ... │ ... ║
╚════════════════╧════════════════╝
Crew
╔════════╤══════════╗
║ CrewId │ SallSign ║ CrewId - Primary Key (used Id 'case crew is usually
╟────────┼──────────╢ shown as crew members - it has no particular
║ 4243 │ Astreus ║ name)
║ 4344 │ Altair ║ CallSign - attribute (it may not be assigned or
║ 4445 │ ... ║ explicitly shown - i.e. it can be NULL)
║ ... │ ... ║
╚════════╧══════════╝
这两个实体通过Flight
互动。每次航班都向国际空间站提供一名机组人员并返回另一名或同一名机组人员。显然Flight
和Crew
之间的关系是多对多的,它需要联结关系(表)。但是,由于宇宙飞船,我们无法将SpaceShip
和Crew
联系起来 - 宇宙飞船可以重复使用(可回收),例如航天飞机。
所以Flight
应该是这样的:
╔═══════════════╤════════════╤═══════════════╤═════╗
║ ShipName │ FlightName │ ShipFlightNum │ ... ║ ShipName, FlightName
╟───────────────┼────────────┼───────────────┼─────╢ are composite PK
║ Soyuz TM-31 │ NULL │ 1 │ ... ║ ShipFlightNum
║ Atlantis │ STS-117 │ 28 │ ... ║ depends on whole
║ Soyuz TMA-14 │ NULL │ 1 │ ... ║ Composite PK
║ Endeavour │ STS-126 │ 22 │ ... ║ ... - other
║ Soyuz TMA-15M │ NULL │ 1 │ ... ║ attributes which
║ Endeavour │ STS-111 │ 18 │ ... ║ depend on PK
║ Atlantis │ STS-122 │ 29 │ ... ║
║ ... │ ... │ ... │ ... ║
╚═══════════════╧════════════╧═══════════════╧═════╝
所以Flight
有复合主键(联盟号车辆的航班名称与航天器的名称相同,但它对于可重复使用的航天器而言是不同的作为航天飞机),它需要与多对多Crew
相关联。这是我的复杂问题的一部分 - 如果这个复合主要自然键应该替换为代理一个?
如果我们进一步使用自然键,那么新的连接关系(关联实体)应如下所示:
Designation
(船员专为飞行而设计)
╔═══════════════╤════════════╤════════╤══════════╗
║ ShipName │ FlightName │ CrewId │ CrewType ║
╟───────────────┼────────────┼────────┼──────────╢
║ Soyuz TMA-15M │ NULL │ 4243 │ Deliver ║
║ Soyuz TMA-15M │ NULL │ 4243 │ Return ║
║ Soyuz TMA-15M │ NULL │ 4445 │ Backup ║
║ Soyuz TMA-16M │ NULL │ 4344 │ Deliver ║
║ Soyuz TMA-17M │ NULL │ 4445 │ Deliver ║
║ Soyuz TMA-18M │ NULL │ 4344 │ Return ║
║ Endeavour │ STS-111 │ 55 │ Deliver ║
║ Endeavour │ STS-111 │ 44 │ Return ║
║ Endeavour │ STS-113 │ 55 │ Return ║
║ ... │ ... │ ... │ ... ║
╚═══════════════╧════════════╧════════╧══════════╝
这里我们有4x 复合主键,它由四个外键组成(CrewType也有FK约束)。如果我们使用 Surrogates 而不是 Naturals ,那么结果会更紧凑但很难填满(在我看来)。
表(关系)TypeCrew
的另一个案例:
╔══════════╗
║ CrewType ║
╟──────────╢
║ Deliver ║
║ Return ║
║ Backup ║
║ ... ║
╚══════════╝
只要我们不在查询中使用这些值(WHERE CrewType LIKE 'Backup'
),就可以了。如果这些值将被替换为其他语言的替代含义,或甚至用符号替换,例如分别为>
,<
和^
的{{1}},Deliver
和Return
(Backup
)。添加数字代理键将无济于事,因为其值可能与WHERE CrewType LIKE '^'
(TypeName
)不匹配:
WHERE TypeId=2
也许这不是关系模型的问题?也许这只是糟糕的设计?但我无法设计得更好。
答案 0 :(得分:0)
使用代理键的优缺点列表很好。正如该清单所示,这个主题很复杂。并且在数据库设计者之间没有关于何时指示或禁止代理键的统一共识。即使在这个Q&amp; A区域,你会发现关于这个主题的各种各样的观点。
我对你的“无意义”列表嗤之以鼻,认为这是使用代理键的一个缺点。在许多情况下,它们毫无意义的事实是一个优点,而不是一个缺点。特别是,人们发明的许多自然键不是“原子的”。也就是说,它们包含在密钥内编码的多个属性。
例如,在给定车辆的VIN(车辆识别号)的情况下,是否可以确定车辆的乘客座位容量。但这是最初制造的座位容量,而不一定是目前的座位容量。由于VIN应该是不可变的,所以当一个座位被撕掉时它不能改变。它现在误导了。
许多数据库设计教师提倡无意义的密钥。
使用自然键的名称存在一些缺点,您没有提及。它们通常不是唯一的,并且它们通常是可变的,如人类所使用的那样。例如,一所大学可能有两名学生名叫Mary Jones。或者玛丽琼斯可能会将她的名字改为玛丽史密斯,一个学期的一部分。
你没有提到另一个缺点。这是错误的数据,包括欺诈。如果SSN用于识别员工,我们必须防止员工给我们一个假的SSN,然后雇用一个真正拥有该SSN的人。那时数据库真的很麻烦。
这个答案只涉及一个非常大的主题的几个方面。我建议从CJ Date等作者那里进一步阅读。