【问题标题】:MySql table design: multiple tables vs. multiple columnsMySql 表设计:多表 vs. 多列
【发布时间】:2009-10-29 03:40:30
【问题描述】:

我对处理相对大量表字段的理想方法感到困惑,以及是否应该将它们拆分为单独的关系表。

我有一组用于基于网络的游戏的表格,包含玩家数据、物品数据、类数据等。对于其中的每一个(玩家/物品/类),我还需要记录一个统计数据的数量(即健康、精神、盔甲等)。目前该列表有 25 个统计信息,这意味着这些表中的每一个除了已有的列之外,还有 50 个附加列(类型/值对)。

这开始感觉很麻烦。

另一种方法是将所有统计数据移动到单独的表格中。例如,项目统计信息位于“项目统计关系”表中,ID 链接到项目和统计表。

如果我需要更改统计数据的数量,这将简化表结构并提供灵活性。但是,它也增加了维护数据的复杂性。如果我添加一个新项目,而不仅仅是在项目表中插入一行,我现在必须在“项目统计关系”表中插入更多行以包含它需要的所有统计信息。

是否值得为保持表格简单而付出额外的努力?


编辑:忘记添加我正在考虑的另一个选择:将所有统计信息序列化到 VARCHAR 或 TEXT 列中。这也可以让我灵活地添加任意数量的统计信息(特别是如果我使用 TEXT),并且不会给处理它的代码增加任何复杂性。但是,根据我的阅读,TEXT 块对性能不利,我必须相当频繁地访问它,每次都读取和写入整个块。

【问题讨论】:

  • 您熟悉数据库模式规范化吗?
  • 并非如此。在谷歌搜索我的问题的答案时,我偶然提到了它,但并不完全知道它的含义。

标签: sql mysql


【解决方案1】:

另一种方法是将所有统计数据移动到单独的表格中。例如,项目统计信息位于“项目统计关系”表中,ID 链接到项目和统计表。

这是处理业务规则的正确方法。

如果我添加一个新项目,而不仅仅是在项目表中插入一行,我现在必须在“项目统计关系”表中插入更多行以包含它需要的所有统计信息。

仅当该项目实际使用该属性时。它允许一个项目/等关联 0+ 个统计信息,这意味着您永远不必为每个新统计信息更新数据模型来添加一列。

当您冒着不良数据的风险时,没有性能优势。你所做的,将被你必须执行的黑客攻击吃掉。

...对多个项目使用 MySQL 函数(即,将玩家拥有的所有项目的“强度”相加),如果其中一些项目甚至没有该统计的记录...

用途:

   SELECT IFNULL(SUM(t.value), 0)
     FROM PLAYERS p
     JOIN ITEM_STAT_RELATION itr ON itr.player_id = t.player_id
LEFT JOIN STATS s ON s.stat_id = itr.stat_id
    WHERE p.player_id = ?
      AND ...

LEFT JOIN 用于指示可能不存在支持记录,IFNULL 旨在处理这种情况,因为它的值将为空。 SUM 可以处理 NULL - 它将值解释为零。

...将所有统计信息序列化到 VARCHAR 或 TEXT 列中。

不要这样做
如果您想报告特定统计数据或一组统计数据,则连接统计数据列表将很难提取详细信息。由于字符限制,它存在无法将每个统计信息存储在单个列中的风险。

【讨论】:

  • 非常好!并非所有项目都具有所有统计数据。但是,它确实让我想知道您是否仍然可以在多个项目上使用 MySQL 函数(即,将玩家拥有的所有项目的“强度”相加),如果其中一些项目甚至没有该统计数据的记录...
【解决方案2】:

不确定我是否理解此评论:“当前列表是 25 个统计信息,这意味着这些表中的每一个都有 50 个附加列(类型/值对)”我希望每个统计信息都有一列。或者只有 2 列(键/值)和许多额外的行

我本以为例如 player 表会有如下列: 玩家姓名、健康、力量、智力等......

然后每一行将是:

  • MyHero、250、12、11 等...
  • MyOtherHero、200、10、12 等...

添加新的统计数据只是添加一列的情况。对于现有玩家,您可能必须对现有行进行数据修复,使其具有默认值或基于其他统计数据的某个值。

对于玩家可能拥有的物品,您将拥有一个物品表,其中将每个物品作为单独的行包含,例如:

  • 物品编号、物品名称、生命值、护甲等...
  • 1, SwordOfDoom, 10, 200, ...
  • 2, 反射之盾, 8, 300, ...

然后你会有一个链接表来将每个玩家与他们拥有的物品联系起来,所以如果 MyHero 有这两种物品而 MyOtherHero 只有盾牌,我们可能会有一个挥舞表

  • 玩家物品ID
  • 我的英雄,1
  • 我的英雄,2
  • MyOtherHero,2

还是我错过了什么?

【讨论】:

    【解决方案3】:

    在您的情况下,我认为额外的列属于表格。否则,您最终会得到两个具有相同行数且它们之间存在 1:1 映射关系的表。这并没有真正简化任何事情!

    从概念上讲,我认为它也更正确。所有这些列都是直接链接到其行中的项目的数据片段,因此它们属于一起。比如说,如果所有的剑都有一套共同的价值观,那就不一样了。然后你会想说“物品 Foo 是一把剑,所以查看 Class Attribute 表以获取剑物品的统计数据”。

    【讨论】:

      【解决方案4】:

      如果统计信息的数量不会改变,并且您确定不需要新的统计信息,则可以使用单表多列设计,而不是值/对方法。但是,值/对方法很灵活,允许您在不更改现有数据库架构的情况下添加新的统计信息,并节省更多空间。

      需要考虑的一些问题

      1. 是否所有角色/物品都有这 25 个属性?如果不是,最好使用 value/pair
      2. 您是否要合并某些实体没有的新统计数据?如果是这样,请使用值/对

      如果您不想使用值对方法,可以尝试序列化。但这会使统计数据无法搜索(例如,列出所有力量大于 20 的实体就更难了)

      【讨论】:

      • 这是一个很好的观点。我没有考虑过这种搜索的可能性,但我可以看到它非常有用。
      【解决方案5】:

      多表更好,它是规范化的模式

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-11
        • 2018-02-15
        • 2011-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多