【问题标题】:Items and specialized items: Multiple tables with duplicate columns, main table and detail table, or ...?项目和专业项目:具有重复列的多个表、主表和明细表,还是...?
【发布时间】:2012-03-23 23:19:42
【问题描述】:

我需要存储与“项目”相关的数据,其中会有各种不同的项目类型,所有项目类型都有共同的属性,然后每种类型都有自己的附加属性。我希望这是一个常见的要求;什么是最佳实践解决方案?我们正在使用 SQL Server。

让我们用一个虚构的例子:

车辆

  • 价格
  • 制作
  • 型号
  • 所有者

(在我们的真实数据中,会有10-15个常见的列。)

汽车是车辆加号:

  • 风格(轿车、运动等)
  • 颜色
  • 引擎尺寸

是车辆加号:

  • 位移
  • PortOfOrigin

...等等。对于几种类型的东西。在我们的真实数据中,每个特殊类型通常会添加 2-5 列;将有 5 种类型开始。随着时间的推移,我们将添加类型,但总共可能只有 3 或 4 个(如果有的话)。添加类型需要开发,因此它不像最终用户可以随意添加的“标签”。我们假设添加类型将需要更改数据库和客户端层,可能还需要更改中间层。完全没问题。

我们将对所有项目(车辆,在上面的示例中)进行大量查询;我们很少担心特定项目类型(汽车、船)的细节。

我看到了四种存储这些数据的方法:

  1. 用于 Cars、Boats 等的单独表格,具有重复的列。
  2. 一个包含 Vehicle 数据的表,一个包含附加 Car 数据的表,以及一个包含附加 Boat 数据的表。
  3. 一个项目表,一个单独的项目属性表,每个附加属性一行。例如,详细信息的软架构。
  4. 具有通用列的表仅由非数据库代码赋予含义。

查看每个:

  1. 用于 Cars、Boats 等的单独表格,具有重复的列。例如,大致:

    CREATE TABLE [Cars] (
        [Id] IDENTITY PRIMARY KEY,
        [Price] DECIMAL (19, 4),
        [Make] NVARCHAR(200),
        [Model] NVARCHAR(200),
        [Owner] INT,
        [Id] INT PRIMARY KEY,
        [Style] NVARCHAR(200),
        [Color] NVARCHAR(200),
        [EngineSize] DECIMAL(19, 2)
    )
    CREATE TABLE [Boats] (
        [Id] IDENTITY PRIMARY KEY,
        [Price] DECIMAL (19, 4),
        [Make] NVARCHAR(200),
        [Model] NVARCHAR(200),
        [Owner] INT,
        [Id] INT PRIMARY KEY,
        [Displacement] DECIMAL(19, 4),
        [PortOfOrigin] NVARCHAR(200)
    )
    

    很简单,汽车进入Cars,船进入Boats。如果我们添加更多车辆类型,我们会添加一个表格。如果我们添加另一个公共列,我们必须返回并将其添加到所有车辆表中。一般来说,可以针对所有表格的联合视图报告车辆(注意Id 列)。

  2. 一个包含Vehicle 数据的表,一个包含附加Car 数据的表,以及一个包含附加Boat 数据的表。例如,大致:

    CREATE TABLE [Vehicles] (
        [Id] IDENTITY PRIMARY KEY,
        [Price] DECIMAL (19, 4),
        [Make] NVARCHAR(200),
        [Model] NVARCHAR(200),
        [Owner] INT,
        [Type] INT        -- A type ID, e.g. "Car" vs. "Boat"
    )
    CREATE TABLE [Cars] (
        [Id] INT PRIMARY KEY,
        [Style] NVARCHAR(200),
        [Color] NVARCHAR(200),
        [EngineSize] DECIMAL(19, 2)
    )
    CREATE TABLE [Boats] (
        [Id] INT PRIMARY KEY,
        [Displacement] DECIMAL(19, 4),
        [PortOfOrigin] NVARCHAR(200)
    )
    

    所以每辆汽车在Vehicles 中都会有一行,在Cars 中会有一个链接行。每艘船在Vehicles 中将有一行,在Boats 中将有一个链接行。如果我们添加更多车辆类型,我们会添加一个表格。一般而言,可以仅针对Vehicle 表对车辆进行报告。当检索特定CarBoat 的详细信息时,我们使用连接。

  3. 一个项目表,一个单独的项目属性表,每个附加属性一行。例如,详细信息的软模式。例如,大致:

    CREATE TABLE [Vehicles] (
        [Id] IDENTITY PRIMARY KEY,
        [Price] DECIMAL (19, 4),
        [Make] NVARCHAR(200),
        [Model] NVARCHAR(200),
        [Owner] INT,
        [Type] INT
    )
    CREATE TABLE [VehicleDetails] (
        [VehicleId] INT,
        [Name] NVARCHAR(200),
        [Value] NVARCHAR(MAX)
    )
    

    因此,每辆汽车在 Vehicles 中获得一排,在 VehicleDetails 中获得三排(“样式”、“颜色”和“引擎尺寸”各有一个)。报告主要针对Vehicle 表进行。详细报告开始变得非常混乱。软模式有它们的位置,主要是围绕用户定义的数据,但我认为这不是一个好的选择。

  4. 一个具有通用列的表,仅由非数据库代码赋予含义:

    CREATE TABLE [Vehicles] (
        [Id] IDENTITY PRIMARY KEY,
        [Price] DECIMAL (19, 4),
        [Make] NVARCHAR(200),
        [Model] NVARCHAR(200),
        [Owner] INT,
        [Type] INT,
        [Detail01] NVARCHAR(MAX),
        [Detail02] NVARCHAR(MAX),
        [Detail03] NVARCHAR(MAX),
        [Detail04] NVARCHAR(MAX),
        [Detail05] NVARCHAR(MAX),
        [Detail06] NVARCHAR(MAX),
        [Detail07] NVARCHAR(MAX),
        [Detail08] NVARCHAR(MAX),
        [Detail09] NVARCHAR(MAX),
        [Detail10] NVARCHAR(MAX)
    )
    

    所以 Car 数据会将 Style 分配给 Detail01,Color 分配给 Detail02,EngineSize 分配给 Detail03;对于 Boats,我们将 Displacement 放入 Detail01,将 PortOfOrigin 放入 Detail02。同样,最终用户定义的模式可能有一个地方,但我猜当你可以控制数据库结构时,这不是一个好的答案。

【问题讨论】:

  • 关系型数据库有严格要求吗?看起来对这个模型使用文档数据库会更合适。
  • @Oded:好问题。在这种情况下,是的,它必须存储在 RDBMS 中,至少现在是这样。如果我们得到足够多的这类需求,也许我们会用文档数据库来扩充 RDBMS。
  • “随着时间的推移,我们将添加更多类型” - 向我表示选项 2。与通用列一样,软模式(EAV 模型)不是首发。
  • @Oded:是的,我走上了软模式的道路,然后说“那不会很好”。 :-) 为了完整性,主要包括 3 和 4。

标签: sql tsql database-design


【解决方案1】:

视情况而定。

方法 1 最适用于大多数属性对大多数类型都通用的情况。

方法 2 最适合大多数类型通用的属性很少的情况。

方法 3 本质上是方法 1,使用实体-属性-值方法来处理特定于类型的属性。这种方法最适合大多数类型通用的大多数属性的情况,并且很难预测需要哪些附加属性 - 这在需要用户创建字段的情况下很常见。

方法 4 在任何情况下都不是一个好主意 - 它将语义内容从元数据层移除到代码层,同时保留方法 1 的不灵活性。

还有另一种可能的方法 - 纯 Entity-Attribute-Value 方法(基本上是方法 3 和 4 的混合)。由于在 RDBMS 上实现时产生的复杂性和较差的性能,这通常被视为一种反模式。但是,在某些情况下,它是唯一可行的方法 - 主要是在事先不知道实体关系的情况下。

【讨论】:

  • 谢谢,非常合理。我刚刚将此信息添加到问题中:“为了给您一个想法,我们认为将有大约 10-15 个通用属性(例如,车辆数据)和任何给定的专用类型(汽车、船)将增加 2-4。” 所以这表明你倾向于选项 1...?
  • @T.J.Crowder - 我会说你需要考虑你期望有多少额外的类型。量少,减1,量大,减2。
  • @Oded:谢谢,您已经强调了我没有提及的其他内容。 :-) 我已经添加了。 (一开始有五种类型,随着时间的推移可能不会超过另外三四种。)
  • @T.J.Crowder:我个人倾向于方法 1,因为每种类型可能具有的附加属性数量相对较少。不过,我认为你比我更适合打这个电话。
  • @MarkBannister:谢谢。是的,归根结底,我们必须用我们的真实模式来决定这一点,但很高兴知道其他人的想法。
猜你喜欢
  • 1970-01-01
  • 2016-10-27
  • 2019-06-13
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-11
  • 2021-06-03
相关资源
最近更新 更多