Database design 在关系数据库中实现1到0..1关系的正确方法

Database design 在关系数据库中实现1到0..1关系的正确方法,database-design,relational-database,database-normalization,Database Design,Relational Database,Database Normalization,想象一下,在我们的数据模型中有一个实体(数据结构),它有可选的部分。我们可以将这些“部分”实现为对其他(子)实体的可空引用。换言之,主实体的每个实例可能具有或不具有与其关联的其他(子)实体的单个实例,并且子实体的任何实例仅具有与其关联的主实体的一个实例。所以我们有1对0的关系 例如,审核日志记录有公共字段(时间戳、用户、操作)和操作特定部分(扩展信息),对于不同的操作,这些字段可能完全不同。我们可以使用单独的实体来表示每种类型的扩展信息,然后使主实体具有对每种可能的扩展信息类型的可空引用 我可以

想象一下,在我们的数据模型中有一个实体(数据结构),它有可选的部分。我们可以将这些“部分”实现为对其他(子)实体的可空引用。换言之,主实体的每个实例可能具有或不具有与其关联的其他(子)实体的单个实例,并且子实体的任何实例仅具有与其关联的主实体的一个实例。所以我们有1对0的关系

例如,审核日志记录有公共字段(时间戳、用户、操作)和操作特定部分(扩展信息),对于不同的操作,这些字段可能完全不同。我们可以使用单独的实体来表示每种类型的扩展信息,然后使主实体具有对每种可能的扩展信息类型的可空引用

我可以看到在关系数据库中实现它的两种方法:

1.主记录中对子实体的可空引用 对于每种类型的子实体,主记录表都有一个字段作为外键引用子(扩展)表中记录的ID

这似乎是更直接的选择:要检索相关信息,我们只需遵循直接引用。在SQL查询中,我们将通过外键左键联接子(扩展)表。外键的Null值将为所有子表的字段提供Null值

2.子实体的记录引用主实体的记录 我们不在主实体表中存储任何引用。相反,子实体表的每条记录都引用主表中ID为外键的记录。在SQL查询中,我们仍然将联接子表留给主表,并且对于没有相应子记录的所有子表字段,我们都会得到空值

??? 哪种方法是正确的?第二个似乎更相关,我们不必在主表中创建额外的字段,但从技术上讲,可能需要更多的工作来查找相关记录,因为我们必须在子表中搜索主ID,而不是直接引用。或者DB引擎是否优化了这种连接以使其快速,例如使用索引?索引搜索比扫描快,但比直接引用慢。加上索引占用空间。我填补了DB引擎工作原理知识的不足。。。或者我只是错过了一些显而易见的事情。非常感谢您的帮助

更新
在得到下面的答案后,也进行了一些思考,并决定使用第二种方法。除了被接受的答案中所说的内容(从关系的角度来看更紧凑、更正确,不必处理空值),如果我需要删除主记录和所有相应的子记录,它还提供了使用级联删除的良好可能性。

在这种情况下,我认为“最佳”解决方案取决于数据库的工作负载,因为这两种解决方案各有优缺点

第二种解决方案没有空值,这通常会使查询复杂化(空值也会使解决方案对关系模型的纯粹主义者来说不“正确”),但也有其他好处:它需要更少的空间(因此对于某些类型的操作,关系更紧凑,需要更少的操作时间)。另一方面,它需要连接来访问详细数据(因此需要为这些操作提供额外的索引)

第一种解决方案在概念上更简单,在访问详细数据时不需要连接,但需要更多的空间,这会减慢某些类型的操作

这两种解决方案都在实际环境中使用

我认为,只有知道应用程序的典型工作负载必须部署在这样的数据库上,才能解决这个难题:某些查询相对于其他查询是否更频繁(或必须具有更少的延迟)?例如,只查看一般数据的查询比需要详细数据的查询使用得更频繁

最后,如果很难或不可能进行这种“理论”分析,唯一的其他方法是尝试一种解决方案,但如果性能不令人满意,则准备尝试另一种解决方案。这可以通过使用视图来实现,例如:

  • 从第二个解决方案开始,定义一个进行连接的视图

  • 适当时,使用基表或联接视图编写应用程序

  • 如果性能不令人满意,则通过join创建一个与旧视图同名的新表,切换到另一个解决方案,并定义一个新视图,该视图仅对NOTNULL属性执行投影


  • 通过在这两种情况下为视图和基表交换相同的名称,应用程序只需要最少的一组修改,您可以尝试这两种方法。

    在这种情况下,我认为“最佳”解决方案取决于数据库的工作负载,因为这两种解决方案各有优缺点

    第二种解决方案没有空值,这通常会使查询复杂化(空值也会使解决方案对关系模型的纯粹主义者来说不“正确”),但也有其他好处:它需要更少的空间(因此对于某些类型的操作,关系更紧凑,需要更少的操作时间)。另一方面,它需要连接来访问详细数据(因此需要为这些操作提供额外的索引)

    第一种解决方案在概念上更简单,在访问详细数据时不需要连接,但需要更多的空间,这会减慢某些类型的操作

    这两种解决方案都在实际环境中使用

    我认为,只有知道哪一个是典型的工作负载,才能解决这个难题