【问题标题】:Database design: objects with different attributes数据库设计:具有不同属性的对象
【发布时间】:2011-02-12 10:34:18
【问题描述】:

我正在设计一个产品数据库,其中产品可以根据其类型具有非常不同的属性,但每种类型的属性都是固定的,并且类型根本无法管理。例如:

杂志:标题、issue_number、页数、副本、close_date、release_date
web_site:名称、带宽、点击次数、date_from、date_to

我想使用 InnoDB 并在引擎允许的范围内强制执行数据库完整性。处理此问题的推荐方法是什么?

我讨厌那些表有 100 列并且大多数值都是 NULL 的设计,所以我想到了这样的事情:

product_type
============

product_type_id INT
product_type_name VARCHAR

product
=======

product_id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME

magazine
========

magazine_id INT
title VARCHAR
product_id INT -> Foreign key to product.product_id
issue_number INT
pages INT
copies INT
close_date DATETIME
release_date DATETIME

web_site
========

web_site_id INT
name VARCHAR
product_id INT -> Foreign key to product.product_id
bandwidth INT
hits INT
date_from DATETIME
date_to DATETIME

这可以处理级联产品删除,但是......好吧,我并不完全相信......

【问题讨论】:

    标签: mysql database-design innodb


    【解决方案1】:

    这是针对关系表阻抗不匹配的经典 OO 设计。您描述的表格设计称为“每个子类的表格”。与您的对象在您的应用中的实际外观相比,三种最常见的设计都是妥协:

    1. 每个具体类的表
    2. 每个层次结构的表
    3. 每个子类的表

    您不喜欢的设计——“表有 100 列,大部分值为 NULL”——是 2. 一个存储整个专业化层次结构的表。由于各种原因,这是最不灵活的,包括 - 如果您的应用程序需要新的子类,则需要添加列。您描述的设计可以更好地适应变化,因为您可以通过添加由 product_type 中的值描述的新子类表来扩展它。

    剩下的选项 - 1. 每个具体类的表 - 通常是不可取的,因为在实现每个专业化表中的所有公共字段时涉及重复。虽然,优点是您不需要执行任何连接,并且子类表甚至可以位于非常大的系统中的不同数据库实例上。

    您描述的设计完全可行。下面的变化是使用 ORM 工具执行 CRUD 操作时的外观。注意每个子类表中的 ID 如何是层次结构中父表的 FK 值。一个好的 ORM 将仅根据 product.id 和 product.product_type_id 中的鉴别器值自动管理正确的子类表 CRUD。无论您是否计划使用 ORM,请查看 hibernate 加入的子类文档,如果只是查看他们做出的设计决策。

    product
    =======
    
    id INT
    product_name VARCHAR
    product_type_id INT -> Foreign key to product_type.product_type_id
    valid_since DATETIME
    valid_to DATETIME
    
    magazine
    ========
    
    id INT -> Foreign key to product.product_id
    title VARCHAR
    ..
    
    web_site
    ========
    
    id INT -> Foreign key to product.product_id INT
    name VARCHAR
    ..
    

    【讨论】:

    • 对三种可能设计的很好的概述,谢谢。所有答案都很好,但我只能选择一个<:-)
    【解决方案2】:

    您似乎大致走在了正确的轨道上,但您可能需要考虑“产品”与通常称为“库存单位”(SKU) 之间的区别。一盒 25 个单位的回形针(某种特定种类的)与 50 个单位的盒子是否是相同的“产品”?就商店或任何种类的库存系统而言,区别很重要;实际上,在某些情况下,包装中的简单区别可能会为您提供不同的 SKU 来跟踪。

    如果这对您的应用程序很重要,您需要决定在哪里跟踪此问题(可以按照您的方式布置产品,并在其他表中处理用于 SKU 目的的包装,例如例如,即使对于某些可能会产生轻微开销的应用程序)。

    【讨论】:

      【解决方案3】:

      这实际上是在经典 RDBMS 中“实施”一种 OO 设计的标准方法。

      所有“通用”属性都放在主表上(例如价格,如果它在产品表级别维护,很容易成为主表的一部分),而细节放在子表上。

      理论上,如果您有子子类型(例如,杂志可以在日报和 4 色期刊中进​​行子类型,也许,期刊具有保质期的日期间隔)您也可以添加一个或多个子级别。 ..

      这是非常常见(且经过验证)的设计。唯一需要担心的是,对于大多数操作,主表将始终与至少一个子表连接。如果您有数以万计的项目,这可能会对性能产生影响。

      另一方面,像删除项目这样的常见操作(我建议进行逻辑删除,在主表上将标志设置为“true”)将对每种子类型执行一次。

      不管怎样,去吧。也许在谷歌周围搜索“面向对象的 RDBMS 映射”或 a complete discussion 之类的东西。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-14
        • 2015-06-30
        • 1970-01-01
        • 1970-01-01
        • 2015-09-09
        • 2022-07-03
        • 2017-03-29
        • 2020-07-18
        相关资源
        最近更新 更多