【问题标题】:How would you model data variables variance on common scheme? SQL您将如何对通用方案的数据变量方差进行建模? SQL
【发布时间】:2010-10-14 08:00:29
【问题描述】:

我最近在考虑一些事情,我想知道做类似以下场景的正确方法是什么(我相信数据库人员做类似的事情是很常见的事情)。

假设你有一个 products 表,像这样 (MySQL):

CREATE TABLE `products` (
  `id` int(11) NOT NULL auto_increment,
  `product_name` varchar(255) default NULL,
  `product_description` text,
  KEY `id` (`id`),
  KEY `product_name` (`product_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

这里没有什么特别之处。现在假设在不同的表中有一个类别的层次结构,并且有一个单独的表将多对多关系与 products 表绑定 - 这样每个产品都属于某种类别(我将省略那些,因为这不是这里的问题)。

现在到了有趣的部分——如果每个类别都要求产品项目附加一组变量。例如,计算机显示器类别中的产品必须具有 LCD/CRT 枚举字段、屏幕尺寸枚举等 - 以及其他一些类别,假设冰淇淋有一些其他变量,如风味 varchar、货架存储时间 int 等。

这里的问题在于所有产品都有一组共同的变量(id、name、description 和类似的),但是还有其他变量在类别之间不一致 - 但所有产品都应该共享共同的集合,因为最后它们都属于产品组,因此可以查询例如 SELECT * FROM products ORDER BY company_id (简单的例子,可能不具有代表性,但你明白了)。

现在,我看到了几个潜在的解决方案:
- 为每个产品类别生成单独的表,并在其中存储带有适当附加变量的产品 - 愚蠢且查询不友好

- 产品表与公共变量保持相同,并为每个类别创建一个单独的表,其中包含附加变量,将两个表与 JOIN 绑定 - 标准化,但查询性能和清晰度问题 - 如何从类别中过滤产品(第一个表 - 产品) 和用于额外变量的附加过滤器(即 17" LCD 显示器。) - 它需要 SQL JOIN 技巧

- 产品表保持不变并添加另一个变量类型的文本,例如包含其他变量的 JSON 数据 - 紧凑且整洁,但无法使用 SQL 过滤变量

我知道我在这里遗漏了一些非常明显和简单的东西——我对标准化技术有点生疏了:)


编辑:在没有成功提出这个问题之前,我一直在搜索 stackoverflow。然而,在我发布问题后,我点击了我的标签“规范化”之一,发现了几个类似的问题,导致查找“泛化专业化关系设计”。故事的重点是,这一定是我的互联网生活中第一次出现标签在搜索中真正有用的情况。但是,我仍然想听听你们的意见和意见。
edit2:方法 2 的问题是我预计大约 1000 个专业化。类别有一个层次结构(1-4 级深),端节点添加了专门的变量 - 它们以大约 1000 个的顺序累积,因此添加专门的表来连接有点不切实际。
edit3:由于在我的案例中存在大量属性波动,建议的“实体属性值”看起来像是要走的路。查询噩梦来了!多谢你们。

【问题讨论】:

    标签: sql mysql database database-design normalization


    【解决方案1】:

    我一直在 Oracle 这样做。

    我有以下表格:

    t_class (id RAW(16), parent RAW(16)) -- holds class hierachy.
    t_property (class RAW(16), property VARCHAR) -- holds class members.
    t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances
    t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds 'common' properties
    
    t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds 'fast' properties for class1.
    t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds 'fast' properties for class2
    --- etc.
    

    RAW(16)Oracle 的位置 GUIDs

    如果你想选择一个对象的所有属性,你发出:

    SELECT  i.*
    FROM    (
            SELECT  id 
            FROM    t_class
            START WITH
                    id = (SELECT class FROM t_declaration WHERE id = :object_id)
            CONNECT BY
                    parent = PRIOR id
            ) c
    JOIN    property p
    ON      p.class = c.id
    LEFT JOIN
            t_instance i
    ON      i.id = :object_id
            AND i.class = p.class
            AND i.property = p.property
    

    t_property 包含您通常不会搜索的内容(例如,文字描述等)

    Fast 属性实际上是数据库中的普通表,以提高查询效率。它们只为某个类或其后代的实例保存值。这是为了避免额外的连接。

    您不必使用快速表并将所有数据限制在这四个表中。

    对于您的任务,它看起来像这样(为简洁起见,我将使用方括号中的字符串而不是 GUID):

    t_class 标识父母 [ClassItem] [ClassUnknown] [ClassMonitor] [ClassItem] [ClassLCD] [ClassMonitor] t_property 类属性 [ClassItem] 价格 [ClassItem] 供应商 [ClassItem] 模型 [ClassMonitor] 大小 [ClassLCD] 矩阵类型 t_declaration 身份证类 [1] [ClassLCD] -- 饭山 ProLite E1700 t_instance -- 我会将所有值放在一列中,不考虑类型(INT、VARCHAR 等) id 类属性值 [1] [ClassItem] 价格 $300 [1] [ClassItem] 供应商饭山 [1] [ClassItem] 型号 ProLite E1700s [1] [ClassMonitor] 尺寸 17 [1] [ClassLCD] matrixType TFT

    如果您需要一些复杂的查询来搜索 size AND matrixType,您可以将它们从 propertyinstance 中删除并创建另一个表:

    t_lcd (id RAW(16), 大小 INT, matrixType VARCHAR2(200)) id 大小 matrixType [1] 17 TFT

    并使用它来连接其他属性,而不是上面查询中的t_declaration

    但即使没有快速表,这种模型也是可行的。

    【讨论】:

    • 嗯,所以如果我理解正确 - 你做了我所说的第二种解决方案吗?每个专业都有额外的变量单独的表?
    • 只有在需要提高性能时才会创建单独的表(我称它们为快速属性)。我会更新帖子并更详细地描述它。
    【解决方案2】:

    您期望有多少种产品类型?他们每个人都有自己的应用程序逻辑吗?

    您可以创建一个称为“实体属性值”模型的通用模型,但是当您尝试处理产品的特定属性时,它有很多陷阱。简单的搜索查询有时会变成真正的噩梦。基本思想是您有一个包含产品 ID、属性名称(或属性表中的 ID)和值的表。您还可以添加表格以保存每种产品类型的模板。因此,一组表格会告诉您任何给定产品的属性(可能还有有效的值范围),而另一组表格会告诉您任何单个产品的值是什么。

    我强烈警告不要使用此模型,因为在您必须实际实施之前,这似乎是一个非常巧妙的想法。

    如果您的产品类型数量有限,我会选择您的第二种解决方案 - 一个具有基本属性的主产品表,然后为每种特定类型的产品添加附加表。

    【讨论】:

    • 方法 2 的问题是我预计大约 1000 个专业化。有一个层次结构(1-4 级深)的类别和终端节点添加专门的变量 - 它们以 ~1000 的顺序累积
    • 在这种情况下,您的应用程序可能成为 EAV 模型的候选者。请记住,如果您想使用特定属性(而不仅仅是列出所有属性),那么使用起来会变得非常困难。
    【解决方案3】:

    这种模式有一个名字。它被称为“泛化专业化”。

    如果您搜索“泛化专业化建模”,您会看到一些关于如何做到这一点的文章。其中一些文章倾向于关系建模和 SQL,而另一些则倾向于对象建模。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      相关资源
      最近更新 更多