中低复杂度数据库外键使用决策:数量取舍与边界探讨
数据库外键设置边界与网状Schema优化疑问
核心疑问
重新设计一套中低复杂度的数据库Schema时,到底是大量密集设置外键连接实体/表更好,还是尽量少设外键更合适?该如何把握边界?
外键与连接的关联度低于其对数据库完整性的保障作用。证据在于你可以以任何方式连接表,哪怕毫无意义。
我的数据库Schema内部分表间存在大量关联,实体关系图呈密集网状,而非规整的中心辐射结构。因数据分批导入,通过Entity Framework设置的诸多外键列为可选,待导入完成后数据会最终一致。我在不影响导入的前提下尽可能设外键,却导致部分表高度关联,产生代码异味。
代码异味问题
核心用例「获取创建Analysis所需全部数据」涉及的表连接数持续增加,目前维护着一个包含多表的大型PostgreSQL View,且还会扩大。部分数据仅需单次连接,但有些需多层嵌套连接,这对表量不多的系统而言是明显的代码异味。
系统背景
这是药房福利相关系统,收集标准化数据并整合内部数据后,通过大型SQL查询呈现给工作人员,工作人员分析后创建Suggestion。从CRUD角度看系统简单,性能层面无需限制外键数量;仅查询环节,创建Analysis的全量数据查询需多次表连接,存在困难。
潜在解决方案
- 输入驱动方案:按数据源拆分数据,编写服务和查询分别拉取,但跨源数据本身关联且有直接外键关系,此方案不可行。
- 领域驱动方案:无法解决代码异味,所有数据属于同一领域。
- 中心辐射式架构:尝试将含外键的表设为中心,但不同中心内实体关联强于同中心,核心实体本就高度关联,设单一中心无意义。
- 接受网状结构:实体关系呈杂乱网状,虽导致查询代码异味,但或许应接受现状?
实体关系补充
| 实体 | 关系 | 关联实体 |
|---|---|---|
| Claim(理赔单) | many : 1 | Prescription(处方) |
| Claim(理赔单) | many : 1 | Pharmacy(药房) |
| Claim(理赔单) | many : 1 | Prescriber(开方医生) |
| Claim(理赔单) | many : 1 | Plan(福利计划) |
| Claim(理赔单) | many : 1 | Plan Member(计划成员) |
| Claim(理赔单) | many : 1 | Formulary(处方集) |
| Claim(理赔单) | many : 1 | Formulary Row(处方集明细行) |
| Claim(理赔单) | many : many | Analysis(分析记录) |
| Claim(理赔单) | many : many | Suggestion(建议) |
| Prescription(处方) | many : 1 | Prescriber(开方医生) |
| Prescription(处方) | many : 1 | Plan Member(计划成员) |
| Prescription(处方) | many : 1 | Formulary Row(处方集明细行) |
| Prescription(处方) | many : many | Analysis(分析记录) |
| Prescription(处方) | many : many | Suggestion(建议) |
| Pharmacy(药房) | many : many | Plan(福利计划) |
| Pharmacy(药房) | many : many | Analysis(分析记录) |
| Pharmacy(药房) | many : many | Suggestion(建议) |
| Prescriber(开方医生) | many : many | Analysis(分析记录) |
| Prescriber(开方医生) | 1 : many | Suggestion(建议) |
| Plan(福利计划) | 1 : many | Plan Member(计划成员) |
| Plan(福利计划) | 1 : 1 | Formulary(处方集) |
| Plan(福利计划) | 1 : many | Analysis(分析记录) |
| Plan(福利计划) | 1 : many | Suggestion(建议) |
| Plan Member(计划成员) | many : 1 | Formulary(处方集) |
| Plan Member(计划成员) | 1 : many | Analysis(分析记录) |
| Plan Member(计划成员) | 1 : many | Suggestion(建议) |
| Formulary(处方集) | 1 : many | Formulary Row(处方集明细行) |
| Formulary(处方集) | 1 : many | Analysis(分析记录) |
| Formulary(处方集) | 1 : many | Suggestion(建议) |
| Formulary Row(处方集明细行) | many : many | Analysis(分析记录) |
| Formulary Row(处方集明细行) | many : many | Suggestion(建议) |
| Analysis(分析记录) | 1 : many | Suggestion(建议) |
内容的提问来源于stack exchange,提问作者Gregory Ledray
相关产品推荐
相关产品推荐

