【问题标题】:Database design - which would be better?数据库设计——哪个更好?
【发布时间】:2013-10-07 08:15:57
【问题描述】:

我有多个表。

它们都有以下字段:

item_title | item_description | item_thumbnail | item_keywords

我最好有一个带有额外 item_type 字段的 items_table,然后加入相应的表,还是将它们全部保存在单独的表中?

【问题讨论】:

  • 检查link
  • 感谢 Nadeem,但该链接正在尝试获取是否将所有列拆分为行更好的设计。我只想知道单个项目表而不是许多单独的表是否更好。
  • 为了使讨论简短——是的,你的想法很好,这就是要走的路。
  • 您没有提供足够的数据来给出完整的答案。这个问题的答案不能是确定的,而是假设的,因为除了你之外没有人知道你的全部意思。类型会增长吗?您目前有多少张桌子 3、30、300、3000?您需要如何最频繁地查询这些数据?都是为了一个类型还是通过其他方式?...等等。最好的设计是基于需求的,有时可能会对数据库进行反规范化以获得更好的性能。

标签: mysql database database-design


【解决方案1】:

取决于上下文。如果您的商品几乎没有差异化,并且您确定您不会在 6 个月、12 个月、2 年内遇到需要将商品分开的情况,那么请走一个通用的路线“项目”表。如果特定项目类型确实有特定要求,那么您可以创建一个包含此数据的单独表,并在查询时创建一个LEFT JOIN 以包含额外数据。

我还建议查看其他数据库类型。从您的场景来看(大量项目类型,存储的数据差异很小),我认为您可能会受益于像 MongoDB 这样的基于文档的数据库引擎,而不是像 MySQL 这样的基于关系数据的数据库引擎。

【讨论】:

  • 谢谢@Martin Bean,我真的按照每个项目类型都需要自己的表格的方式进行,但是它们都有许多共同的字段,因此应该将这些字段整理到一个大表中?
  • 如果不知道您的业务目标,我无法肯定地说,但如果在您的代码中,所有不同的项目都可以扩展具有相同字段的通用 Item 类,那么我会说这表明它们也应该存储在一个单一的 items 表中。
【解决方案2】:

好的,所以表共享字段。他们是否也共享约束1

  • 如果是,则继续将它们合并在一起。
  • 如果不是,您可以将它们分开,或者可以将它们合并在一起,这取决于您愿意做出什么样的权衡。

例如,如果表具有单独的外键,则可以将它们分开,或者可以将它们合并到一个表中,但将 FK 分开:

item_title
item_description
item_thumbnail
item_keywords
table1_id REFERENCES table1 (table1_id)
table2_id REFERENCES table2 (table2_id)
...
CHECK (
    (table1_id IS NOT NULL AND table2_id IS NULL ...)
    OR (table1_id IS NULL AND table2_id IS NOT NULL ...)
    ...
)

(注意:MySQL 不强制执行 CHECK,因此您需要从触发器或客户端代码执行等效的强制执行,或者尽可能使用不同的 DBMS。)

我需要更多地了解您的数据库,以确定哪个更好。

带有一个额外的 item_type 字段,然后加入相应的表,

永远不要在代码中强制执行 FK,如果可以的话。即使您将表合并在一起,也不要合并 FK,而是执行上述操作。在并发环境(其中多个客户端可以尝试同时修改相同数据)的上下文中在代码中强制执行 FK 很难做到正确并且具有良好的性能 - 最好让DBMS 为您完成。

顺便说一句,item_keywords 是什么?它是一个以逗号分隔的关键字列表(或类似关键字),您需要进一步规范化并将关键字提取到它们自己的单独表格中。


1 域(数据类型和 CHECK)、键(PRIMARY KEY 和 UNIQUE)和引用(FOREIGN KEY)约束。

【讨论】:

    【解决方案3】:

    我相信桌子越少越好。它易于维护。很难想象如果你有 3000 种类型的item_type。然后,将有 3,000 个不同的表。所以在你的情况下,单张桌子对我来说是个好主意。以后遇到需要分表的情况,可以轻松做到。

    所以简短的回答是,YES

    【讨论】:

      【解决方案4】:

      如果我理解得很好,您只需要规范化您的架构:

      项目:

      item_id
      item_name
      item_description
      

      items_types

      item_id
      type_id
      

      类型

      type_id
      item_file_name
      

      所以这样你就可以拥有任意数量的任意类型的项目

      这是你想做的吗???

      【讨论】:

      • 谢谢 Sal00n.. 看来我所有的表格,例如文件、用户、页面、帖子都只是基本上由以下列组成的列表: item_id |项目名称 | item_description | item_filename .. 将所有这些放在一个表中并有一个额外的字段来区分 item_type 会不会更好.. 例如文件 /post 等
      • 那么将所有数据放在同一个表中也许是个好主意。
      【解决方案5】:

      我建议你用一张表item,一张表type,原因如下(假设有10种)。

      1. 我不确定您使用的是哪种编程语言。作为一名 Java 开发人员,如果我有多个表,我将不得不为每种类型创建每个实体类。所以我宁愿只有一个类,并且有一个类型作为属性。
      2. 当您必须在同一页面中显示所有类型时,您必须从所有 10 个表中针对 10 种类型执行选择查询。
      3. 当您引入一种新类型时,您必须为 CRUD 和业务特定操作编写代码。开发人员将继续为每种新类型添加代码。

      基本上,如果您有一个用于项目的表和一个用于类型的表,则您不必为您引入的每种新类型更改数据库架构和代码。但是如果您确定类型的数量较少并且不会改变,您可以考虑使用多表。

      【讨论】:

        【解决方案6】:

        创建两个单独的表并根据您所需的输出将它们连接起来。

        即>

        1.1'st TABLE(主表==>item_type)

        item_type(item_type_id,item_type_name,状态)

        2.2'nd TABLE(子表==>item_details)

        item_details(item_id,item_type_id,item_title,item_description,item_thumbnail,item_keywords)

        See more examples..

        【讨论】:

          【解决方案7】:

          我觉得signle table会更合适。它将避免更多的连接,程序(代码)中的复杂性以及多个表的比较错误。即使从管理的角度来看也会更好,比如数据库集群等。

          【讨论】:

            【解决方案8】:

            如果您有很多表需要具有相同的重复列,那么是的,这是为公共字段创建单独表的好方法。如果这些重复的列不是固定的并且可以更改,例如在常见的默认列列表中再添加一列,这会更有效。

            那你怎么能做到呢?

            这个想法是创建一个单独的表并将常用的默认列放在那里。 该表就像一个虚拟表,即可以根据需要添加/删除列。

            例如-

            表格 - DefaultFields

            - item_title | item_description | item_thumbnail | item_keywords

            您还可以在循环中动态插入DefaultFields 表中的值,例如:

            "INSERT INTO DefaultFields (item_table, item_title , item_description,item_thumbnail ,item_keywords) VALUES('"+ field.item_table + "','" + field.item_title + "','" + field.item_description+ "','" + field.item_thumbnail  + "','" + field.item_keywords)");
            

            注意: 字段是在表格循环中保存值的对象。

            然后您可以进一步更改您的表格以从 DefaultFields 表格创建这些默认字段,例如:

              "ALTER TABLE " + item_table+ " ADD COLUMN [" + field.item_title + "] Text"
            

            可以对每个表重复此操作以根据需要对其进行更改。

            在这个设计模式中,即使你想:

            1) 再添加一列或

            2) 删除预先存在的列或

            3) 更改预先存在的列名

            然后您可以在虚拟表中执行此操作,其余部分由相应表中的 ALTER table 命令更新。

            【讨论】:

              【解决方案9】:

              在我看来...我会说不,永远不会。

              有两个原因:

              • 您确实希望在数据库中保留逻辑含义。现在,它的组织方式对您来说非常明显。但在两个月(或一年)内,会如此明显吗?如果有人加入这个项目,他是否更容易理解你的应用程序的不同逻辑块是否分开?我的意思是... 人和猫确实是动物。将它们放在同一个盒子里仍然合乎逻辑吗?

              • 性能。表格越短,您的请求就越快。数据仍将占用磁盘上的空间。而且我不谈论了解您正在寻找哪种类型的项目的比较。我的意思是,如果你想选择应用程序的所有页面,只需比较两个请求:

              多个表:

              Select * from pages_tbl;
              

              单表:

              Select * from item_tbl where type = 'page';
              

              您将从这个设计中获得什么?没有性能,没有磁盘空间,没有可读性。我真的看不出有什么好的理由。

              【讨论】:

              • 您给出的第一个原因在所提供的上下文中是零意义的。 “假设”是无效的论点。您给出的第二个原因完全无效并且没有任何意义,您需要研究 MySQL 特别是如何工作和存储数据(鉴于您知道使用哪个引擎的事实)。话虽如此,您提供的答案纯粹是自以为是并客观地看待它 - 这是一个糟糕的答案,这就是我不赞成它的原因。正确的答案是,将列表数据放在一个由 1 个属性区分的表中会更有效。
              • 谢谢@N.B. ,如果情况仍然如此,我在徘徊,如果每个 item_type 都必须为 items 表中未涵盖的字段拥有自己的表? ...因此,您总是需要执行连接来获取所有项目数据。