我正在考虑如何在SQLServer数据库中表示一个复杂的结构。
考虑一个应用程序,它需要存储一系列对象的详细信息,这些对象共享一些属性,但有许多其他不常见的属性。例如,商业保险套餐可能包括同一保单记录中的责任险、汽车险、财产险和赔偿险。
在c#等中实现这一点很简单,因为您可以创建一个包含节集合的策略,其中节是根据各种类型的保险单的需要继承的。然而,关系数据库似乎并不容易做到这一点。
我可以看到有两个主要的选择:
为所有可能的变体创建一个策略表,然后创建一个节表,其中包含所有必需的字段,其中大部分为空。
创建一个policy表和多个section表,每种cover对应一个。
这两种方法似乎都不能令人满意,尤其是在需要跨所有部分编写查询时,这将涉及大量连接或大量空检查。
这种情况下的最佳实践是什么?
8条答案
按热度按时间6jygbczu1#
或者,考虑使用本机支持丰富数据结构和嵌套的文档数据库(如mongodb)。
s4chpxco2#
我倾向于方法#1(一个统一的节表),以便有效地检索整个策略及其所有节(我假设您的系统将做很多)。
此外,我不知道您使用的是哪个版本的SQLServer,但在2008年,稀疏列有助于优化性能,因为在这种情况下,列中的许多值都将为null。
最终,您必须决定策略部分的“相似性”。除非他们有实质性的不同,我认为一个更规范化的解决方案可能会比它的价值更麻烦。。。但只有你能打电话
mdfafbf13#
此外,在daniel vassallo解决方案中,如果您使用sql server 2016+,我还使用了另一种解决方案,在某些情况下不会造成性能损失。
您可以创建一个只包含公共字段的表,并添加一个包含所有子类型特定字段的json字符串的列。
我已经为管理继承测试了这个设计,我很高兴我可以在相关的应用程序中使用这种灵活性。
iqjalb3h4#
看看我在这里给出的答案
fluent-nhibernate合成键一对一Map
rbl8hiat5#
@billkarwin在他的sql反模式书中描述了三种继承模型,当时他提出了sql实体属性值反模式的解决方案。以下是简要概述:
单表继承(也称为每层次表继承):
在第一个选项中使用单个表可能是最简单的设计。正如您所提到的,许多特定于子类型的属性必须被赋予
NULL
这些属性不适用的行上的值。使用此模型,您将有一个policies表,该表如下所示:保持设计简单是一个优点,但这种方法的主要问题如下:
在添加新的子类型时,必须修改表以适应描述这些新对象的属性。当您有许多子类型时,或者如果您计划定期添加子类型,这很快就会成为问题。
由于没有元数据来定义哪些属性属于哪些子类型,数据库将无法强制应用哪些属性,哪些不应用。
你也不能强制执行
NOT NULL
在子类型的属性上,应该是强制的。您必须在应用程序中处理这个问题,这通常并不理想。具体表继承:
处理继承的另一种方法是为每个子类型创建一个新表,重复每个表中的所有公共属性。例如:
这种设计基本上解决了单表法存在的问题:
强制属性现在可以通过
NOT NULL
.添加新的子类型需要添加新表,而不是向现有表中添加列。
也不存在为特定子类型(例如
vehicle_reg_no
属性策略的字段。没有必要这样做
type
属性作为单表方法中的属性。类型现在由元数据定义:表名。然而,这种模式也有一些缺点:
公共属性与特定于子类型的属性混合在一起,没有简单的方法来识别它们。数据库也不会知道。
定义表时,必须为每个子类型表重复公共属性。那绝对不干。
无论子类型如何,都很难搜索所有策略,并且需要大量的
UNION
s。这是您必须查询所有策略的方式,而不考虑其类型:
请注意,添加新的子类型将如何要求使用附加的
UNION ALL
对于每个子类型。如果忘记此操作,很容易导致应用程序出现错误。类表继承(也称为每类型表继承):
这就是@david在另一个答案中提到的解决方案。为基类创建一个表,其中包含所有公共属性。然后为每个子类型创建特定的表,其主键也充当基表的外键。例子:
此解决方案解决了其他两种设计中发现的问题:
强制属性可以通过
NOT NULL
.添加新的子类型需要添加新表,而不是向现有表中添加列。
没有为特定子类型设置不适当属性的风险。
不需要这个
type
属性。现在公共属性不再与子类型特定属性混合。
我们终于可以保持干燥了。在创建表时,不需要重复每个子类型表的公共属性。
管理自动递增
id
因为策略变得更容易,因为这可以由基表处理,而不是由每个子类型表独立地生成它们。无论子类型如何,搜索所有策略现在变得非常容易:否
UNION
需要-只是一个SELECT * FROM policies
.我认为类表方法在大多数情况下是最合适的。
这三个模型的名称来自martinfowler的《企业应用程序体系结构模式》一书。
anhgbhbe6#
第三个选项是创建一个“policy”表,然后创建一个“sectionsmain”表,该表存储跨节类型通用的所有字段。然后为每种类型的节创建其他表,这些表只包含不常见的字段。
决定哪一个是最好的主要取决于您有多少字段以及您希望如何编写sql。他们都会工作。如果你只有几个字段,那么我可能会选择1。有了“很多”字段,我会倾向于2或3。
bsxbgnwa7#
根据提供的信息,我将对数据库进行建模,使其具有以下特性:
政策
策略id(主键)
负债
密码(主键)
策略id(外键)
属性
属性\u id(主键)
策略id(外键)
…以此类推,因为我希望策略的每个部分都有不同的属性。否则,可能只有一个
SECTIONS
除了policy_id
,会有一个section_type_code
...无论哪种方式,这都允许您支持每个策略的可选部分。。。
我不明白您对这种方法有什么不满意的地方—这就是您在保持引用完整性和不复制数据的同时存储数据的方式。术语是“标准化”。。。
因为sql是基于集合的,所以它与过程/oo编程概念相当陌生&需要代码从一个领域转换到另一个领域。orm经常被考虑,但是它们在高容量、复杂的系统中不能很好地工作。
qqrboqgw8#
另一种方法是使用
INHERITS
组件。例如:因此,可以在表之间定义继承。