【问题标题】:Is CHECK better then invalid data?CHECK 比无效数据好吗?
【发布时间】:2025-12-16 06:10:01
【问题描述】:

我正在为数据库编写代码。我有一张包含机器活动日志的表格,如下所示:

CREATE TABLE Work(  
   id SERIAL PRIMARY KEY,   
   machine_ID integer NOT NULL DEFAULT 0,   
   start_work timestamp,
   etc...
);

我知道 machine_ID 可以在 1 到 5 之间。

我的问题来了: 使用CHECK(machine_ID >= 1 AND machine_ID <=5) 有什么好处吗? 接受被污染的数据,以便以后修复可能出现的错误,甚至利用清理数据的可能性不是更好吗?

【问题讨论】:

  • 我总是使用检查约束。仅在极少数情况下才允许使用无效数据
  • +1。您真的不希望数据库中有垃圾。一旦它在那里,就很难摆脱它。
  • 您假设“受污染”的数据 a) 易于识别且 b) 可修复。这些事情是否属实在很大程度上取决于您的具体情况。 IE。如果机器 3 开始将自己报告为机器 4,即使检查约束也无济于事。
  • 检查约束可能会让您更快地发现问题,因为它会引发错误,而存储污染数据则需要您对其进行定期检查。但是,它会消耗一些处理能力,并且会阻止存储行的任何部分(无论是否被污染),因此您可能需要围绕它对插入该数据的任何部分进行编程(例如在 XX 分钟后重试错误)。跨度>

标签: sql postgresql database-design


【解决方案1】:

也许这更适合作为评论。

但不应使用check 约束来验证名为machine_id 的列。相反,您应该有一个表——比如machines——这是机器的参考表。

您的代码应使用foreign key 约束。这是一种特殊类型的数据验证,称为关系完整性

至于你的问题。根据我的经验,通常最好在错误进入数据库时​​捕获它们。数据库中的错误数据通常会导致更进一步的问题——这些问题本可以避免。

【讨论】:

    【解决方案2】:

    如果您想限制 id 在您的数据库中的数量,那将是可以的,但仅此而已。

    【讨论】:

    • 你的意思是,支票只用于那个目的?
    • 是的,就是这样。
    【解决方案3】:

    这是非常主观的,有不同的方法和意见,并且高度依赖于您的业务案例。

    一个原则是让事情保持简单,但即使是 的意思是主观的。


    • 提前拒绝

      在预处理层中,将规则应用于接收的数据。尽快拒绝任何行/文件/源并请求重新提交。

      这样就明确了哪些已经被接受,哪些没有被接受,如何处理这样的场景等等。


    • 什么都吃

      在故障可能复杂多样的情况下,数据库通常是进行分析以了解故障的根源、原因、严重程度和/或影响的最佳场所。在这种情况下,摄取一切可能是有益的。

      但这可能会产生潜在的无法控制的影响。因此,我对此的一般经验是在数据库中有一个单独的暂存区。本质上尽可能非结构化,以允许尽可能多的数据。但即使这样也并不总是有帮助。如果对所有字段都使用字符串,则可以接受通常必须接受的数据。但即便如此,如果您有一个包含 9 列的文件为 8 列的表提供怎么办?您可以接受整行作为单个字符串,但分析它以获得有意义的结果几乎是不可能的。


    这在您的情况下意味着什么取决于您正在从事的项目,这就是您没有描述的内容。

    我个人的默认立场是将某些源数据故障重新归类为预测/一切照旧的不一致。然后,您可以构建暂存区域来处理这些问题,用于报告、对账、补救措施等。更重要的是,将它们明确地构建到所有相关的业务流程中。这样做会引入成本,可以根据容纳它们的好处来估算成本,目的是仅在实际上是物质利益的情况下容纳不一致。 (而不仅仅是一个囤积者,为了以防万一有一天它可能对某人有所帮助。)

    然而,无论往哪个方向发展,操作数据库本身(不是暂存区)都是高度结构化的,具有完整性约束,以防止错误、意外输入等破坏现有数据或导致意外、不受监控的后果。

    如果您真的相信您的操作数据库(无论是事务型、分析型还是其他)会因缺少部分/许多/所有这些数据完整性工具而受益,那么 SQL 关系数据库对你来说可能是错误的工具。而是考虑大量的非结构化数据存储和处理平台。

    【讨论】:

      【解决方案4】:

      有很多不同的考虑因素。

      首先,我不希望对可能更改的业务规则使用检查约束 - 我不想推出数据库架构更改(并且检查约束是架构更改)以响应可预测的业务事件.添加或删除机器感觉就像是可预测的业务事件;所以正如@gordonLinoff 建议的那样,我建议对“机器”表使用外键。

      其次,我不喜欢“隐藏代码”——从开发和维护的角度来看,我喜欢让所有的验证尽可能地易于理解。检查约束和触发器相对“隐藏”,难以记录,难以调试,难以测试非平凡用例;另一方面,外键是显式的,开发人员期望它们。

      【讨论】: