SQL反模式07-多态关联
条评论允许用户对bug记录进行评论,我们很容易设计出一个一对多的关系。但是随着需求变更,可以进行评论的可能是多张表,比如bug和feature_request都可以进行评论,就会有类似以下的关系。
1 | -- 错误的语句,仅用于表现关系 |
目的:关联多个父表
本章目的很明确,就是要处理多个父表关联同一子表的情况。
反模式:使用多用途外键
这个解决方案已经正式命名了,那就是多态关联,或者叫杂乱关联。
定义多态关联
为了使用多态关联,你需要多添加一列issue_type用来标识issue_id属于bug还是feature_request,如下
1 | create table comment( |
你会发现使用该设计,issue_id外键没有了,因此就没有任何保障数据完整性的手段来确保issue_id是否存在其父表中。同样的也没有一个约束来保证issue_type是否为一个有效值。
使用多态关联进行查询
1 | select * from comment c |
如何识别反模式:当出现以下情况时,可能是反模式
- 这种标记框架可以让你将标记(或者其他属性)和数据库中的任何其他资源联系起来。就想EAV的设计一样,应该怀疑任何生成有无线扩展性的设计。
- 不能在数据库中声明外键。
- 有一列,用来说明这条记录的其他列是和什么相关的。任何外键都强制一张表中所有的行引用同一张表。
合理使用反模式:
应该尽量避免使用多态关联,应该使用外键约束等来确保引用完整性。
因为:多态关联通常过度依赖上层程序设计而不是数据库的元数据。
解决方案:让关系变得简单
既要避免使用多态关联的缺点,又要支持你需要的数据模型,最好就是重新设计数据库,接下来就是要帮你解决这个难题。
反向引用
当你看清本质时,解决方案异常简单:多态关联是一个反向关联。
创建交叉表
comment无法创建外键,是因为多个外键引用comment表,那么我们为每个外键创建一张独立的交叉表。如下
1 | create table bug_comment( |
这个设计模式,元数据可以确保数据完整性。
缺点:如果有更多的类型,你需要创建更多这样的交叉表。联结查询需要多关联一张表。
共用超级表
创建一个基类表,并让所有的父表都继承该基类表,关系图如下
1 | create table issue( |
给定一个评论,你可以通过一个相对简单的查询就获取对应的bug记录或者feature记录,而不再需要在查询中包含issue表,除非你将一些属性定义在那张表,同样的,由于bug表的主键和他的祖先issue表中的值时一样的,你可以直接对bug和comment表进行关联查询。也可以对两张没有外键约束直接关联的表进行联结查询,只要对应的列的信息是可比较的即可。
1 | select * from comment as c |
对于一个指定bug,你同样可以轻易的查出他的评论
1 | select * from bug as b |
更重要的是如果你是用了像issue这样的祖先表,就可以依赖外键来确保数据完整性。
在每一个表与表的关系中,都有一个引用表和一个被引用表。
总结
看完这章,总感觉有点过度设计,我觉得学习以下作者思考的思路就好了,或者以后也用得上这一章的内容。
- 本文链接:https://www.ofcoder.com/2018/08/04/sql/antipatterns/07-%E5%A4%9A%E6%80%81%E5%85%B3%E8%81%94/
- 版权声明:Copyright © 并发笔记 - ofcoder.com. Author by far.
分享