代码之家  ›  专栏  ›  技术社区  ›  Moak

具有多列的单个固定表与灵活的抽象表

  •  25
  • Moak  · 技术社区  · 15 年前


    示例商店:

    shop_id | name | X | Y | city | district | area | metro | station | address | phone | email | website | opening_hours
    

    或者类似的更抽象的方法:

    object_id | name        
    ---------------
    1         | Messy Joe's  
    2         | Bate's Motel 
    
    type_id | name
    ---------------
    1       | hotel
    2       | restaurant
    
    
    object_id | type_id
    ---------------
    1         | 2
    2         | 1
    
    field_id | name           | field_type
    ---------------
    1        | address        | text
    2        | opening_hours  | date 
    3        | speciality     | text
    
    type_id | field_id
    ---------------
    1       | 1
    1       | 2
    2       | 1
    2       | 3
    
    object_id | field_id | value
    1         | 1        | 1st street....
    1         | 3        | English Cuisine
    

    当然,如果值是预定义的,那么它会更抽象(例如:专业可以有自己的列表)

    但我不知道这是否会影响性能,执行这些“更复杂”的查询。

    5 回复  |  直到 10 年前
        1
  •  81
  •   PerformanceDBA    15 年前

    某些问题需要澄清和解决 之前 我们可以进行合理的讨论。

    1. 标签
      在一个要求精确的职业中,重要的是我们要使用精确的标签,避免混淆,这样我们就可以不必使用冗长的描述和限定符就可以进行交流。

      你所张贴的固定资料是 不规范 . 公平地说,这可能是对第三种标准格式的尝试,但实际上它是一个平面文件,不标准化(不是“非标准化”)。准确地说,你发布的抽象表是, 实体属性值 ,它几乎是,但不完全是,第六正规形式,因此比3NF更正规化。当然,前提是做得正确。

      • 为了去正规化,它必须先正规化,然后由于一些好的原因,正规化稍微退后。因为它一开始就没有标准化,所以不能去标准化。这完全是不正常的。

      • 它不能说是“为了表现”的非规范化,因为作为一个表现狂,它是表现的对立面。嗯,他们需要一个理由来证明缺乏形式化的设计,而“为了性能”就是这样。即使是最小的正式审查也暴露了错误陈述(但很少有人能提供,所以它仍然是隐藏的,直到他们让一个局外人来解决,你猜,这是一个巨大的性能问题)。

      • 标准化结构的性能远远优于非标准化结构。更多的标准化结构(EAV/6NF)比更少的标准化结构(3NF/5NF)表现更好。

      • 我同意OMG小马的主旨,但不同意它们的标签和定义

      • 而不是说 不要“非标准化”,除非你必须 ,我是说, '忠实正常化,句号' '如果存在性能问题,则说明您没有正确进行正常化' .
    2. 维基

      .
      然而,为了取得进展,不让这一提法构成障碍,让我这样说。

      • 3NF的定义是稳定的,没有改变。
      • 3NF和5NF之间的NFs有很多混淆。事实是,这一领域在过去15年中取得了进步;许多组织、学术界人士以及产品有局限性的供应商,纷纷创建新的“正常形式”来验证他们的产品。都是为了商业利益,学术上也不健全。3NF在其原始的无阻尼状态下,预期并保证某些属性。
      • 总的来说,5NF是今天,3NF是15年前的打算,你可以跳过商业玩笑和12个左右的“特殊”(商业和伪学术)NFs,其中一些在Wiki中被识别,甚至在混乱的术语中。
        .
    3. 由于您已经能够理解和实现您的文章中的EAV,您将没有问题理解以下内容。当然,真正的关系模型是先决条件、强键等。 第五范式 因为我们跳过了第四个:

        • 简单来说就是,每个表中的每个非键列都与表的主键有1:1的关系,
        • 以及其他非键列
      • 零重复数据(如果正常化是通过努力进行的,则其结果不是仅凭智力或经验,或作为一个目标而无需正式流程来实现的)
      • 无更新异常(当您在某个地方更新列时,不必更新位于其他地方的同一列;该列只存在于一个地方)。
    4. 第六范式 当然是第五种正常形式,加上:


      • .

    5. 我写的所有数据库,除了一个,都是纯5NF。我使用(管理的、修复的、增强的)两个EAV数据库,并且实现了一个真正的6NF数据库。EAV是6NF的松散实现,通常由那些对规范化和NFs没有很好把握,但能够看到EAV的价值并需要其灵活性的人来完成。你是个很好的例子。不同之处在于:因为它是松散的,而且由于实现者没有可信赖的引用(6NF),所以他们只实现他们所需要的,并且他们都用代码编写;结果是一个不一致的模型。

      然而,一个纯6NF实现确实有一个纯学术的参考点,因此它通常更紧密、一致。通常这在两个可见元素中显示:
      • 6NF有一个包含元数据的目录,所有内容都是在元数据中定义的,而不是在代码中定义的。EAV没有,一切都在代码中(实现者跟踪对象和属性)。显然,目录简化了列的添加、导航,并允许形成实用程序。

      • .
        对于带有目录的6NF数据库,我有一组过程,这些过程将[重新]生成执行所有select所需的SQL,并且我为所有用户提供5NF中的视图,因此他们不需要知道或理解底层的6NF结构。他们被逐出目录。因此,更改是容易和自动化的。由于缺少目录,EAV类型手动执行此操作。

    现在,我们可以开始

    讨论

    “当然,如果 值是预定义的(例如: 专业可以有自己的

    当然。但不要太“抽象”。保持一致性,并以与其他列表相同的EAV(或6NF)方式实现这些列表。

    “如果我采取抽象的方法 可以非常灵活,但是查询将 但我不知道这是否会影响 性能,执行这些“更多”

    1. 关联在关系数据库中是步行的。问题不在数据库,问题是SQL在处理连接时很麻烦,特别是复合键。
    2. EAV和6NF数据库有更多的连接,这些连接就像行人一样,不多不少。如果必须手动对每个SELECT进行编码,当然,繁琐的操作会变得非常麻烦。
    3. 这是一个共同的神话,加入不知何故有代价。完全错误。连接是在编译时实现的,没有什么实质性的“消耗”CPU周期。问题在于要联接的表的大小,而不是这些表之间联接的成本。在正确的PKFK关系上连接两个表,每个表都有数百万行,每个表都有适当的索引(父[FK]端唯一;子端唯一);如果子索引不是唯一的,但至少前导列是有效的,则速度较慢;如果没有有用的索引,则速度当然很慢。这与加入成本无关。在返回许多行的地方,瓶颈将是网络和磁盘布局,而不是连接处理。
    4. 因此,您可以随心所欲地获得“复杂”,不需要任何成本,SQL可以处理它。

    我很想知道 我可以自己想象,但我 没有经验可以证实 这个。

    1. 5NF(对于那些没有取得进展的人来说是3NF)在实现、易用性(开发人员和用户)、维护方面是最简单和最好的。缺点是,每次添加列时,都必须更改数据库结构(表DDL)。这在有些情况下是可以的,但在大多数情况下不是,由于控制权变更到位,相当繁重。第二,您必须更改现有代码(处理新列的代码不计算在内,因为这是必需的):在实现好的标准的地方,这是最小化的;在没有标准的地方,范围是不可预测的。

    2. EAV(这是您发布的内容)允许添加列而不更改DDL。这是人们选择它的唯一原因。(处理新列的代码不计算在内,因为这是必需的)。如果实现得好,它将不会影响现有的代码;否则,它将影响现有的代码。但您需要具备EAV功能的开发人员。当EAV实现得不好时,它是可憎的,比5NF做得不好更糟糕,但并不比Unnormalised更糟糕,这是大多数数据库都有的(被误称为“性能非规范化”)。当然,保存一个强事务上下文(比5NF/3NF中的更重要),因为列的分布更广。同样,保留声明性引用完整性也是非常重要的:我看到的混乱很大程度上是由于开发人员删除了DRI,因为它变得“太难维护”,结果是,正如您可以想象的那样,一个数据堆的一个母亲,到处都是重复的3NF/5NF行和列。以及不一致的空处理。

    3. 假设服务器已合理配置为预期用途,则性能没有差异。(好吧,有一些特定的优化只有在6NF中才可能实现,而在其他nf中是不可能的,但我认为这超出了这个线程的范围。)而且,EAV做得不好可能导致不必要的瓶颈,只不过是不正常的。

    4. 当然,如果您使用EAV,我建议您使用更正式的方式;购买完整的quid;使用6NF;实现目录;生成SQL的实用程序;视图;一致地处理丢失的数据;完全消除空值。这减少了您对开发人员质量的脆弱性;他们可以忘记EAV/6NF深奥的问题,使用视图,并专注于应用程序逻辑。

        2
  •  9
  •   Community Mohan Dere    8 年前

    在你的问题中,你同时提出了至少两个主要问题。这两个问题是E-A-V和gen-spec。

    首先,让我们来谈谈E-A-V。您的最后一个表(object-id,field-id,value)本质上是一个E-A-V。E-A-V有一个优点,E-A-V有一个缺点。优点是这个结构非常通用,几乎可以容纳描述任何主题的任何数据体。这意味着您可以继续进行设计和实现,而不必进行数据分析,也不必理解主题,也不必担心错误的假设。缺点是,在检索时,您必须在构建数据库之前进行跳过的数据分析,以便提出任何有意义的查询。这比单纯的检索效率要严重得多。但你也会在检索效率上遇到可怕的问题。要了解这个陷阱,只有两种方法:活过它,或是从那些曾经经历过的人那里读到它。我推荐阅读。

    其次,你有一个发电机规格的情况。您的表(object_id,type_id)捕获一个gen spec(泛化专门化)模式以及相关的表。如果我必须在酒店和餐厅之间进行概括,我可以称之为“公共住宿”或“场所”。但我不确定我是否理解你的情况,你可能是为了比这两个名字所暗示的更一般的东西而开车。毕竟,你已经把“活动”列入了你的清单,在我看来,活动不是一种场所。

    在之前的回答中,我已经让其他人阅读了gen spec和关系模型。
    When two tables are very similar, when should they be combined?

        3
  •  3
  •   mosheb    8 年前

    当您开始需要大量不同的实体(甚至之前…)时,nosql解决方案将比这两种选择都要简单得多。 只需将每个实体/记录与所需的确切字段一起存储。

    {
       "id": 1,
       "type":"Restaurant",
       "name":"Messy Joe",
       "address":"1 Main St.",
       "tags":["asian","fusion","casual"]
    }
    
        4
  •  2
  •   OMG Ponies    15 年前

    “抽象”方法被称为“规范化”,看起来像第三范式(3NF)。

        5
  •  1
  •   sfinnie    15 年前

    代码中的列表是如何表示的?我想 Listing 作为一个超级类型 Shop , Restuarant 等作为子类型?

    • 选项1:每个子类型一个表, 在
    • 选项2:所有对象的单表(您的单表方法)
    • 选项3:父类型的表和每个子类型的表

    没有普遍正确的解决方案。我的偏好通常是从选项3开始;它提供了一个可以使用的初始结构,非常标准化,并且可以很容易地扩展。这意味着检索每个实例只需要一个连接—但是RDBMS在执行连接时经过了很好的优化,因此在实践中不会真正导致性能问题。

    选项2对于查询(没有连接)的性能可能更高,但如果其他表需要引用所有超类型实例(外键激增),则会导致问题。

    选择哪一个,归根结底是要知道你的问题的细节。我建议你多读一点关于选项的书: this article 是一个很好的开始。

    高温高压