【问题标题】:Need a tip on simple MySQL db design需要一个简单的 MySQL 数据库设计技巧
【发布时间】:2010-11-26 23:20:27
【问题描述】:

我正在尝试使用 MySQL 为游戏制作一个简单的项目数据库。这是我的 3 张桌子的样子

项目 项目 ID |项目名称 ------------------ 0001 |胸片 0002 |剑 0003 |头盔 属性(属性查找表) 属性 ID |属性名 --------------------------------- 01 |力量 02 |敏捷 03 |智力 04 |防御 05 |损害 06 |法力 07 |耐力 08 |描述 09 |类型 item_attributes(联结表) 项目 ID |属性 ID |价值(混合型,不好?) ---------------------------------- 0001 | 01 | 35 0001 | 03 | 14 0001 | 09 |盔甲 0001 | 08 |由令人敬畏的精灵制作 0002 | 09 |武器 0002 | 05 | 200 0002 | 02 | 15 0002 | 08 |你的平均剑 0003 | 04 | 9000 0003 | 09 |盔甲 0003 | 06 | 250

我对这个设计的问题是item_attributes表中的value列需要使用varchar数据类型,因为值的数据可以是int、char、varchar。我认为这是一种不好的方法,因为我无法根据特定属性快速对我的项目进行排序。当处理诸如 获取属性强度值在 15 到 35 之间的项目 之类的查询时,它也会受到性能影响。

这是我的潜在解决方案。我只是在attributes 表中添加了一个data_type 列。所以它看起来像这样

属性(属性查找表) 属性 ID |属性名 |数据类型 -------------------------------------------------- - 01 |实力 |整数 09 |类型 |字符 08 |智力| varchar

然后我会在item_attributes 表中再添加 3 列,int、char、varchar。这是新的item_attributes 表的外观。

item_attributes(联结表) 项目 ID |属性 ID |价值 |整数 |字符 | varchar -------------------------------------------------- ---------------------- 0002 | 09 |武器 | null |武器|空值 0002 | 05 | 200 | 200 |空 |空值 0002 | 02 | 15 | 15 |空 |空值 0002 | 08 |你的平均剑|空 |空 |你的平均剑

所以现在如果我要根据其strength 属性对项目进行排序,我将使用int 列。或者根据描述搜索一个项目,我会搜索varchar 列。

但是,我仍然认为我的设计有点奇怪。现在我必须查找attribute 表中的data_type 列,并动态确定item_attributes 表中的哪一列与我要查找的内容相关。

任何意见将不胜感激。

提前致谢。

编辑 2010 年 11 月 29 日 这是我的物品的详细清单

-------------------------------------- http://wow.allakhazam.com/ihtml?27718 奥尔多防御者腿甲 拾取时绑定 腿板 802护甲 +21 力量 +14 敏捷 +21 耐力 物品等级 99 装备: 命中等级提高14。 -------------------------------------- http://wow.allakhazam.com/ihtml?17967 精致的奥妮克希亚鳞片 皮革 物品等级 60 -------------------------------------- http://wow.allakhazam.com/ihtml?27719 奥多强悍护腿 拾取时绑定 腿皮革 202 护甲 +15 敏捷 +21 耐力 物品等级 99 装备: 增加28点攻击力。 装备: 命中等级提高20。 -------------------------------------- http://wow.allakhazam.com/ihtml?5005 余烬火花吊坠 装备时绑定 颈部杂项 +2 耐力 +7 精神 需要 30 级 物品等级 35 -------------------------------------- http://wow.allakhazam.com/ihtml?23234 敏捷的蓝布赖恩石 宝石 需要 2 级 物品等级 10 +8 敏捷 -------------------------------------- http://wow.allakhazam.com/ihtml?32972 啤酒护目镜 拾取时绑定 独特 头杂 物品等级 10 装备: Belbi Quikswitch 保证让每个人看起来都有吸引力! -------------------------------------- http://wow.allakhazam.com/ihtml?41118 加基森礼物 拾取时绑定 独特 物品等级 5 “请回到赛季组织者那里” -------------------------------------- http://wow.allakhazam.com/ihtml?6649 灼热图腾卷轴 独特 任务物品 需要 10 级 物品等级 10 采用: -------------------------------------- http://wow.allakhazam.com/ihtml?6648 石肤图腾卷轴 独特 任务物品 需要 4 级 物品等级 4 采用: -------------------------------------- http://wow.allakhazam.com/ihtml?27864 布莱恩的扩展成本复制的布莱恩特 宝石 物品等级 10 宝石测试附魔 --------------------------------------

编辑#2

  1. 这 10 个示例并不代表我收集的所有 35316 个项目数据。
  • NeckMiscellaneous 表示该项目属于“Neck”和“Misc”两个类别。
  • 唯一意味着角色上只能使用一项。
  • 不要过多解读“行动”,它们只是任务描述
  • 当一个项目显示“装备:增加 28 点攻击力”时,它仅表示玩家角色的攻击力+28。与 +15 敏捷相同。
  • 总共有 241884 条一对多的项目属性记录,因此每个项目的平均属性为 241884/35316 ~= 8 个。数据也从网站挖掘成一个巨大的文本文件。没有“格式正确”的信息来识别项目的类型或类别。因此,如果“剑”一词出现在第 3 行或第 4 行,它会自动归类为剑。
  • 该项目可能会在每次新的游戏更新时发生变化。
  • 除了 `name` 之外,项目之间没有共享通用属性
  • 可通过 Web 应用程序访问项目数据。不清楚您所说的位和向量是什么意思?
  • 在数据挖掘阶段使用正则表达式清理特殊字符并搜索特定关键字以对项目进行分类。还要提取属性名称和值。例如,+15 agility 会将字符串 agility 提取为属性名称,并将 15 作为值。 (我对问题6和6.1不太了解。这里的slog代表服务器日志?将正则表达式翻译成SQL?)
  • Model Diagram

    这是一个查询的示例

    选择 * 来自 itemattributestat 其中 item_itemId=251 item_itemId |属性_attributeId |价值 |列表顺序 ==================================================== ===== “251”、“9”、“0”、“1” “251”、“558”、“0”、“2” “251”、“569”、“0”、“3” '251'、'4'、'802'、'4' “251”、“583”、“21”、“5” “251”、“1”、“14”、“6” “251”、“582”、“21”、“7” “251”、“556”、“99”、“8” “251”、“227”、“14”、“9”

    这里的列表顺序是为了跟踪应该首先列出哪个属性。用于格式化目的

    创建视图 itemDetail 作为 选择 Item_itemId 作为 id,i.name 作为项目,a.name 作为属性,值 from ((itemattributestat join item as i on Item_itemId=i.itemId) 加入属性作为 Attribute_attributeId=a.attributeId) 按 Item_itemId asc、listOrder asc 排序;

    上面的视图产生以下内容

    选择 * 来自itemdetail 其中 id=251; 编号 |项目 |属性 |价值 '251', 'Aldor Defender''s Legplates', '拾取时绑定', '0' '251', 'Aldor Defender' 的腿甲', '腿', '0' '251', 'Aldor Defender''s Legplates', 'Plate', '0' '251', 'Aldor Defender''s Legplates', 'Armor', '802' '251', 'Aldor Defender''s Legplates', '力量', '21' '251', 'Aldor Defender''s Legplates', 'Agility', '14' '251', 'Aldor Defender''s Legplates', 'Stamina', '21' '251', 'Aldor Defender''s Legplates', '物品等级', '99' '251', 'Aldor Defender''s Legplates', 'Equip: 将命中率提高@@.', '14'

    值为 0 的属性表示属性名称代表项目类型。 'Equip: Improves hit rating by @@.', '14' @@ 在这里是占位符,在浏览器上处理后的输出将是'Equip: Improves hit rating by 14.'

    【问题讨论】:

      标签: mysql database


      【解决方案1】:

      为什么你有一个attribute 表?

      属性是列,而不是表。

      网站链接什么也没告诉我们。

      数据库的整体理念是,您可以根据需要为每个查询连接许多小表,因此您需要习惯这一点。当然,它为您提供了一个网格,但它是一个短而甜的网格,没有 Null。您要做的是避免使用桌子;只使用一个充满 Null 的巨大网格。

      (截图)

      不要在属性名(列名)前加上表名,这是多余的。当您开始编写使用多个表的 SQL 时,您会清楚这一点:然后您可以使用表名或别名来为任何不明确的列名添加前缀。

      PK 是个例外,它被完全渲染,并以这种形式使用,无论它是 FK。

      浏览网站,阅读一些 SQL 问题。

      做完之后,以后可以考虑是否要strength和defense成为type的属性(列);或不。等等。

      2010 年 11 月 30 日对评论的回复

      .
      太好了,您了解您的数据。对。现在我明白了为什么你有一个属性表。

      1. 请确保这 10 个示例具有代表性,我正在仔细研究它们。

        • 类型:宝石名称:Emberspark Pendant ... 或者,NeckMiscellaneous 是一种类型吗?
        • Unique 是真正的 ItemType 吗?我认为不是
        • Action.Display "请返回赛季组织者"
        • AttackPower 和 HitRating 的属性在哪里?
          .
      2. 有多少不同类型的项目(共 35,000 个),我的产品集群示例。说明这个问题的另一种方式是,有多少变化。我的意思是,有意义的是,不是 3500 项 ÷ 8 个属性?

      3. item_attributes 会在没有 s/w 版本的情况下更改(例如,新的Inner Strength 属性)吗?

      4. 每个项目,哪些属性重复(不止一个);到目前为止,我只看到 Action ?

      5. 这是一款游戏,因此您需要一个紧凑且非常快速的数据库,可能完全驻留在内存中,对吧。没有空值。没有 VAR 任何东西。最短的数据类型。永远不要重复任何东西(不要重复自己)。您对位(布尔值)和向量满意吗?

      6. 您是否需要轻松地将这些正则表达式转换为 SQL,或者您是否对每个正则表达式都感到满意(即,一旦您让它们在 SQL 中工作,它们就非常稳定,然后您就不会弄乱它,除非您发现一个错误)(没有讽刺,严肃的问题)?

        6.1 或者反过来:数据库是磁盘驻留的;您将其加载到内存中一次;你在游戏过程中运行正则表达式;偶尔写入磁盘。因此不需要将正则表达式转换为 SQL 吗?

      这是我前进方向的数据模型,这完全不确定;它将被你的答案调制。说清楚:

      • 第六范式是行由主键和最多一个属性组成。

      • 我画的是 (6.1) 而不是 (6),因为您的数据强化了我的信念,即您需要一个纯 6NF 关系数据库

      • 我的Product Cluster Data Model,比 EAV 更好的示例,是 6NF,然后通过 DataType 再次规范化(不是正常形式意义上的),以减少您已经看到的表的数量。 (EAV 人通常会选择一张或几张大桌子。)

      • 这是直的5NF,6NF只有右边的2张桌子。

      Link to Game Data Model

      Link to IDEF1X Notation 适用于不熟悉关系建模标准的人。

      2010 年 12 月 5 日对编辑 #2 的回应

      1.1。好的,已更正。

      1.2。那么 IsUnique 是 Item 的指示符(布尔值)。

      1.3。行动。我明白。那么你打算把它存放在哪里呢?

      1.4。 NeckMiscellaneous 表示该项目属于Neck 和Misc 两个类别。 这表示两个独立的Item.Name=Emberspark Pendant,每个都有不同的类别。

      .
      2. 和 5. 所以你确实需要快速快速的内存驻留数据库。这就是为什么我试图让你越过这条线,远离 GridLand,进入 RelationalLand。
      .
      3. 好的,我们使用第五范式,不需要 6NF 或产品集群(每个数据类型的表)。到目前为止,Values 都是整数。
      .
      4.我还能看到:Level,RequiredLevel,IsUnique,BindsPickedUp,BindsEquipped.
      .
      5. 位是布尔值 { 0 | 1}。 (关系)投影需要向量。我们稍后会联系他们。
      .
      6. 好的,你已经解释过了,你没有将正则表达式翻译成 SQL。 (Slog 意味着艰苦的劳动)。 .
      7. 什么是 Category.ParentId ?父类别 ?以前没有出现过。
      .
      8. Attribute.GeneratedId ?

      请评估数据模型(更新)。除了您的专栏之外,我还有一些专栏。如果您对数据模型有任何不明白的地方,请提出具体问题。您已经阅读了 Notation 文档,对吧?

      我有Action 作为表,ItemAction 持有Value:
      Equip: increase attack power by 28 是Action.Name=Increase attack power by 和ItemAction.Value=28。

      【讨论】:

      • @PerformanceDBA:想想看,似乎使用 item_stat 会比 item_attribute 更好。我不能使用您的建议的原因是统计数据的数量因项目而异。同样正如拉里·拉斯提格(Larry Lustig)指出的那样,我需要为将来为物品添加新的统计数据或删除旧的统计数据做准备。
      • @秦。 1) 那么究竟是什么阻止了您在此设计中添加 item_stats 表?没有什么能阻止统计数据的数量变化(它不能在你的网格中变化,但我给你一个关系解决方案)。一对多表在 Rdb 中是正常的。如果您发布项目统计信息的示例,我可以完全回复。 2) 如果您使用 EAV,请先阅读this question and answer。
      • @秦。在这个阶段,我认为没有理由选择 EAV,Rdb 看起来很适合您的目的(您需要发布请求的详细信息);我是说,如果你这样做了,那就好好地去做,不要失去控制。随意发布信息或更改您选择的答案。
      • @秦。在我的帖子里回答了。交给你。另外,请告诉我 Alla Khazam 是否是游戏的正确名称。
      • @秦。在我的帖子里回答了。交给你了。
      【解决方案2】:

      我认为拥有data_type 列只会使设计更加复杂。为什么不简单地将type 和description 列为items 表上的列?理所当然地,每个项目都有这些值,如果没有,那么 null 在文本列中就可以了。

      您甚至可以通过使用item_types 表进一步规范type,items 中的type 列将是该表的数字外键。可能没有必要,但可以更轻松地关闭 items 表上的类型。

      编辑: 进一步考虑这一点,您似乎正在尝试让您的数据表与域模型匹配。在应用程序的逻辑中,您的项目将具有一系列属性。这可以。请记住,您的应用程序逻辑和数据库持久性布局可能不同。事实上,它们在设计层面根本不应该相互依赖。在许多小型应用程序中,它们可能是相同的。但也有例外。代码(可能是面向对象的,但不一定)和关系数据有不同的设计和不同的限制。将它们彼此分离允许开发人员利用他们的设计,而不是受到其限制的阻碍。

      【讨论】:

      • 感谢您的快速响应,在items 表中添加一些通用属性(例如type 和description)的想法是我没有想到的。也许我应该包含更多关于我的设计意图的细节。问题是如果我将sold_by 和dropped_by 都添加到项目中,那么我需要更改item 表。我正在尝试设计一种可以促进项目属性未来变化的设计。
      • @Qin:sold_by 和 dropped_by 是否应该出现在这些表格中?也许保留一张“销售”表和一个“drops”表,每个表都有一个指向items 的外键、时间戳、关于销售/drop 的信息,当然还有一个主 ID。对于任何给定的项目,您可以查询这些表以获取其最近的销售/丢弃/等。很容易。这样你也有一个销售/下降的运行日志,这样数据就不会丢失。应用程序可以将属性作为项目类的单个属性,但数据库不需要。
      • @Qin:您可能还需要查看 MongoDB 等文档数据库以满足您的需求。它的设置与关系数据库非常不同,并且可以很好地适应不断变化的模式。每个项目都可以只是数据库中的一个“文档”,上面有你想要的任何属性。
      • 感谢所有建议。我的站点将部署在共享托管环境中,因此我唯一的数据库选择是 MySQL。您对在哪里包含 sold_by 和 dropped_by 的评论让我对如何定义我的项目和 item_attribute 之间的关系有了新的认识。与其将description 作为属性,不如将description 的值(例如your average sword)用作属性并将其赋值为0。当然,我的属性表现在必须变大。
      • 顺便说一句,我不得不道歉,我对我想要实现的功能不是很坦诚。你可以访问wowhead.com/items 看看我在做什么。
      【解决方案3】:

      您正在处理两个常见问题:

      • 彼此相似但不相同的实体(所有项目都有名称和描述,但不一定是智力)。
      • 一旦数据库投入生产,您就需要在其中添加属性的设计(您可以很容易地预测在某些时候您需要添加,例如,某些项目的魔法抗性属性)。李>

      您通过重新发明将属性名称和值都存储为数据的 EAV 系统解决了您的问题。而且您已经重新发现了这个系统的一些问题(类型检查、关系完整性)。

      在这种情况下,我个人会选择一种介于关系解决方案和 EAV 解决方案之间的解决方案。我会将公共列作为列添加到 items 表中,或者如果 items 代表 kinds 个项目,而不是单个项目,则将它们添加到 items_owners 表中。这些列将包括描述和可能的类型,在您给出的示例中,与文本列非常匹配。然后,我会为那些数字评级的属性保留现有布局,使值类型为 int。这为您提供了跨整数属性的类型检查和适当的规范化(您不会存储大量 NULL),但会牺牲偶尔的 NULL 类型或描述。

      【讨论】:

      • 在谷歌搜索 EAV 是什么之后,我想它可能就是我要找的东西。
      • 完整的 EAV 使您失去了使用关系数据库系统的大部分好处。当您在代码和数据库之间使用对象持久层时最好应用它,它将为您进行类型转换和检查。如果您打算采用这种方法,则可能值得研究满足您的数据存储需求的非 SQL 解决方案(例如对象数据库)。
      • 由于我唯一可以访问的数据库托管是 MySQL,我想我会坚持使用 SQL 解决方案。此外,我的数据库中还有其他领域可以从关系设计中受益。顺便说一句,您能否详细说明“使用对象持久层”,我不确定我是否正在阅读通过搜索谷歌返回的正确内容。
      • 我所说的对象持久层是指您选择的编程语言中的库或功能,它“知道”如何存储语言对象(类实例)并再次检索它们。实现这种功能有不同的方法,一种方法是使用具有巨大 EAV 表的数据库。如果您使用某些产品为您执行与 EAV 表示之间的转换,那么您可以将其视为对象存储。但是,自己做这件事并不好玩。
      • EAV 本身不会影响关系数据库的功能、安全性、完整性和标准。当然,不应该以业余爱好者的工作为例。我曾使用过一些由专业人士制作的商业 EAV 数据库,它们没有丧失完整性或关系能力。您不妨阅读此recent question and answer,DM 解释了如何保持关系能力和 DRI;答案内容解释了如何避免失去任何完整性或控制权。
      猜你喜欢
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 2012-10-24
      • 1970-01-01
      相关资源
      最近更新 更多