在关系数据库中,通常的做法是创建约束来锁定数据及其与其他表的关系。所以,一个Users表可能有一个email列被标记为唯一,因为每个人都有自己的电子邮件,对吧?并且一个Subscription表获得一个不可为空的User列,因为每个订阅都必须与一个用户相关联。是的,这听起来也很合理。

但我在这里反对约束!对于一些听起来可能是异端(或至少非常愚蠢)的人,但请听我说:

我们使用约束有两个原因:性能(搜索唯一索引的列要快得多),以及保证数据完整性(因此我们实际上不能输入无效数据,例如业务需要将订阅绑定到用户)。

问题来了:我们程序员经常优化得太早,而 SQL 约束实际上并没有表达业务需求!

让我分解一下:

  • 关于性能的主题,当然存在约束使查询速度提高几个数量级的有效案例,但除非我们看到该性能问题及其随后的约束补救措施,否则我们冒着过早优化的风险。更少的约束将使代码更具延展性,并减少对数据库结构进行后续更改的摩擦。

我在这里提出的只是我们寻找机会将数据库优化推迟到真正需要它们之前,以抵消我们过早优化的趋势。

  • 确保数据完整性的约束确实受到无法实际捕获所有业务需求的挑战。我的意思是,在 theory 中,数据库约束可以完全表达任何业务需求,因为例如PostgreSQL 方言是图灵完备的,但那太疯狂了!我们不使用 SQL 编程,我们使用 C#、Python、Javascript 等进行编程。实际业务功能属于我们的通用语言,而不是数据存储语言。那么我们应该在数据库中放置什么约束呢?

我建议完全没有业务限制。这听起来是不是疯了?我使用 SQL 的次数越多,我就越容易被半生不熟的“业务约束”所困扰,这种“业务约束”几乎有点重复了代码已经处理的内容。当代码已经确保仅相对于User创建Subscription时,将SubscriptionUser列标记为不可为空的真正给了我们什么?这根本没有帮助,因为约束根本不是事实的实际来源。

但是等等”我听到了一些抗议,“将不可空值添加到User列是如此简单”。是的,但它仍然有害,因为它从根本上不是业务需求的真实来源。

在这一点上,我们需要讨论约束的缺点:它们越多,系统就越难以测试和调整。

  • 更难测试,因为要测试Subscription,我们现在还必须创建User,并正确关联它们。即使测试与User实体无关,也必须创建它。然后想象一下,为了创建一个Subscription,必须将另外一些实体组合在一起,很快就会变得非常痛苦!然后我们可能会开始在实体工厂中隐藏所有测试复杂性,但这些只是我们为自己造成的复杂性之上的抽象。为什么不完全摆脱复杂性?

  • 并且更难以调整,因为引入新功能最终需要仔细迁移以保持约束与代码同步:如果我们实际上可以在没有用户的情况下进行订阅怎么办?如果电子邮件列不必是唯一的怎么办?如果数据存储层施加了人为的约束,它会很快减慢尝试这些想法的速度。

我认为我们中的许多人都会产生限制,因为我们受过培训和/或被告知这样做。但是我们都没有真正在 SQL 中实现 100% 的业务规则,那么,我们在哪里划清界限呢?当约束提供真正的、有形的性能优势时,它们当然是好的,但如果我们放松系统,让这些实体更具延展性,更容易使用和测试,会发生什么?

归根结底,只有您知道您的域,因此我的断言没有一般性的答案。不过,我试图理解的是某种程度的教条,我觉得它潜入了关系存储设计,在这种情况下,我们必须创建听起来与业务逻辑兼容的约束,因为这就是我们的方式。做。相反,我建议只在真正且可证明必要的地方和时间添加一个约束。这样,数据库就可以专注于存储和检索数据,这是它们真正擅长的角色。

照片由Sam Moqadam拍摄于Unsplash

Logo

PostgreSQL社区为您提供最前沿的新闻资讯和知识内容

更多推荐