新的要求出现在旧的代码库上,该代码库基本上实现了两个以前不直接相关的用户类之间的直接(内部)通信(存储在具有完全不同模式的不同表中,并且可悲的是,该代码几乎不面向对象)设计较少,因此没有父类)。由于我们不愿使用这种从未考虑过此功能的旧设置,因此无法保证不存在PK冲突-在使用数据集的情况下,实际上可以保证存在ARE。
因此,解决方案似乎很明显:用火杀死它并重写整个混乱的 A映射表。我已经为实现地图的可能方法提供了两个指导,但是我不是DBA,所以我不确定是否有我遗漏的利弊。
为了阐明抽象,请考虑三组不同的用户数据:教授,行政管理和学生(不,这不是一项家庭作业。应许!)
映射1
(professor_id,admin_id和student_id是它们各自表的外键)
| mailing_id (KEY) | professor_id | admin_id | student_id |
-------------------------------------------------------
| 1001 | NULL | 87 | NULL |
| 1002 | 123 | NULL | NULL |
| 1003 | NULL | NULL | 123 |
这种方法的+/-在缺点上非常繁重:
- 每行两个“浪费”字段
- 违反2NF
- 容易插入/更新异常(例如,只有0-1字段设置为NULL的行)
但是,专业人士并非没有自己的优点:
- 可以通过一次查找完成映射
- 从mailing_id轻松确定给定用户的“源”数据
说实话,直言不讳,我一点都不喜欢这个主意。
对应2
(假设MSG_ *是定义的常量,枚举类型或其他合适的标识符)
| mailing_id (KEY) | user_type (UNIQUE1) | internal_id (UNIQUE2)|
------------------------------------------------------------------
| 1001 | MSG_ADMIN | 87 |
| 1002 | MSG_PROF | 123 |
| 1003 | MSG_STUDENT | 123 |
通过此设置,{user_type,internal_id}的唯一复合索引使情况变得更加清晰,维护了3NF,并且应用程序代码不必检查I / U异常。
不利的一面是,在确定必须在数据库外部处理的用户源表时,会损失一些透明度,这基本上相当于将user_type值映射到表的应用程序级。现在,我(相当强烈)倾向于第二种映射,因为缺点很小。
但是我很痛苦地意识到自己的局限性,并且确定自己可能已经错过了两个方面的优势或绊脚石,因此我转向比我更明智的想法。