MySQL表设计和规范化帮助

时间:2012-11-16 17:37:39

标签: mysql database-design normalization

注意:这个问题已于11/19/12重新定义,以便澄清。我通常在这里没有太多问题,但努力为客户端站点设计新的产品系统。我们提供一套产品,每个客户都可以向他的客户销售。我们可能会随时添加新产品,但它们都遵循以下格式:

  1. 分类
  2. 类型
  3. 产品
  4. 使用之前的结构给出一个真实世界的例子:

       
    • 棒球设备   
           
      • 手套     
               
        • 罗林斯
        •      
        • 耐克
        •      
        • Mizzuno
        •     
           
      •    
      • 蝙蝠     
               
        • 伊斯顿
        •      
        • Louisville Slugger
        •     
           
      •   
       
    •  
    • 足球装备   
           
      • 鞋类     
               
        • 耐克
        •      
        • 锐步
        •      
        • 阿迪达斯
        •     
           
      •    
      • 橄榄球     
               
        • 耐克
        •      
        • Saplding
        •      
        • 威尔逊
        •     
           
      •   
       
    • ....

    上面的列表显然仍在继续,可以更大,更大,但它给出了整体想法。

    目前,我将特定客户可以在单个平面格式表中销售的产品类型存储如下:

    ID  | clientID | categoryID | typeID | productID | customURL
    =============================================================
    1   |  111     |    1       |   1    |   1       | 1111
    2   |  111     |    1       |   2    |   2       | 2222
    3   |  111     |    1       |   2    |   3       | 3333
    4   |  111     |    2       |   3    |   4       | 4444
    5   |  222     |    1       |   1    |   1       | 5555
    6   |  222     |    2       |   3    |   4       | 6666
    
    • 在上面的示例中,类别1可以是“棒球装备”,类别2是“足球装备”
    • 相应的categoryID,typeID和productID的名称将存储在3个具有FK关系(innodb)的seaprate表中,以便维持规范化。
    • 类型指的是二级物品(手套,蝙蝠,鞋子,足球等)。这些数字永远不会相交(意味着即使一般产品是相同的,也永远不会有相同的类型ID(棒球鞋的鞋子比鞋子的鞋子要多)。
    • 在此表中,clientID 1可以销售4个产品,3个类别1个,1个类别2个.ClientID 2可以销售2个产品,每个类别一个。

    我倾向于保持表的结构,但在其他设计中我知道我可能已将表分开以进行标准化目的我不确定是否适用于此处。如果我把它们分解出去,我会看到这个从一个表到4个或更多如下:

    productsOffered table

    ID  | clientID | productID | customURL
    ======================================
    1   |  111     | 1       | 1111
    2   |  111     | 2       | 2222
    3   |  111     | 3       | 3333
    4   |  111     | 4       | 4444
    5   |  222     | 1       | 5555
    6   |  222     | 4       | 6666
    

    productsDefinition Table

    ID  | productID | typeID | productName
    ======================================
    1   |  1        |    1   | rawlings glove
    2   |  2        |    2   | product2
    3   |  3        |    2   | product3
    4   |  4        |    3   | product4
    

    typeDefinition表

    ID  | typeID | categoryID | typeName
    =====================================
    1   |  1     |    1       | Gloves
    2   |  2     |    1       | Bats
    3   |  3     |    2       | Shoes
    4   |  4     |    2       | Footballs
    

    categoriesDefinition Table

    ID  | categoryID | catName
    =============================
    1   |  1         | Baseball Equipment
    2   |  2         | Football Equipment
    

    我在想这个吗?两种方法都不能以相同的方式获得最终解决方案(后者只涉及几个连接以收集平面表,如图1所示)?

4 个答案:

答案 0 :(得分:9)

规范化的目的和好处是它使得输入异常数据变得更加困难(理想情况下,不可能)。

例如,在图1中,有什么可以防止您意外存储带有typeid 3和categoryid 1的行?除了编写非常完美的应用程序代码之外,没什么。

但是如果您使用单表方法,并且您必须更改typeid 3的父类别,则必须更改数百万个位置的数据以反映更改。这意味着在执行清理时锁定表,否则可以同时插入新数据。

规范化有助于消除冗余存储信息,如果每个离散事实(例如,typeid 3属于categoryid 2)只存储一次,那么很容易以原子方式进行更改,并自动更改对该行的所有引用的含义

你是对的,需要更多的连接 - 但只有你像你一样在整个地方使用伪oke。您不一定需要这样做,您可以使用自然键,并且使用级联外键声明对它们的引用,因此查找表中的更改也会自动更新引用表。

当然规范化的规则不要求使用伪讽刺。这些规则对他们一无所知。


重新发表评论:伪名称surrogate key是用于标识行的“id”列。通常,这些值是通过自动递增机制分配的,该机制确保唯一性,同时允许并发事务插入行。 id的值对于它标识的行没有意义。


下面显示了您的表格在正常形式下的外观,但没有代理键。

productsOffered table

client | product        | customURL
===================================
Smith  | Rawlings Glove | 1111
Smith  | Product 2      | 2222
Smith  | Product 3      | 3333
Smith  | Product 4      | 4444
Jones  | Rawlings Glove | 5555
Jones  | Product 4      | 6666

productsDefinition Table

product        | type
=======================
Rawlings Glove | Gloves
Product 2      | Bats
Product 3      | Bats
Product 4      | Shoes

typeDefinition表

type      | category
==============================
Gloves    | Baseball Equipment
Bats      | Baseball Equipment
Shoes     | Football Equipment
Footballs | Football Equipment

categoriesDefinition Table

category
==================
Baseball Equipment
Football Equipment

完全符合关系数据库设计和规范化,使用非整数作为主键列的数据类型,因此外键从其他表引用它们。

出于性能或简洁或允许其他列中的值自由更改,有充分的理由使用代理键。但规范化并未强制要求使用代理键。

答案 1 :(得分:1)

我会选择标准化的方法,因为你必须使用平面方法为类别和类型名称(以及可能的其他属性)维护单独的查找表。

您可以考虑使用以下表格将类别和类型更改为常规树结构:

 create table product_hierarchy(
    id integer primary key,
    name character,
    parent_id references product_hierarchy)

...因为它可以让客户灵活地为层次结构添加更多深度。

答案 2 :(得分:1)

试图解决您的直接问题:

  

我在想这个吗?

取决于您的应用程序的大小,以及您用于存储数据的引擎。由于您计划将其放入MySQL表中,因此您的想法非常合适。

  

两种方法都不能以同样的方式获得最终解决方案(后者只是   涉及几个连接以收集平台,如图1)所示?

嗯,是的,但是quote Wikipedia

  

数据库规范化是组织字段和过程的过程   关系数据库的表,以最小化冗余和依赖性。   规范化通常涉及将大表分成较小的(和   表格和定义它们之间的关系。该   目标是隔离数据,以便添加,删除和   可以仅在一个表中进行字段的修改   通过定义的数据库传播通过数据库的其余部分   关系。

将数据分解为您描述的结构(顺便说一下,我同意这一点),这样您就可以轻松地维护数据。将类别和类型数据保存在与“提供的产品”相同的表中会产生大量冗余数据。当然,我无法想象您需要更新数据的位置,但如果您这样做,则必须更新大量记录。在您提出的结构中,要更新的记录数量很少。

答案 3 :(得分:0)

在第一种方法中,您忘记了每个类别,类型和产品ID的名称列。如果您添加此信息,它可以工作,但其他方法似乎已经工作。当您使用4个不同的表时,您将拥有更多空间。