在这个数据库中不使用规范化表是否很糟糕?
Posted
技术标签:
【中文标题】在这个数据库中不使用规范化表是否很糟糕?【英文标题】:Is it bad to not use normalised tables in this database?在这个数据库中不使用规范化表是不是很糟糕? 【发布时间】:2011-03-05 18:17:09 【问题描述】:我最近在我的信息学课上学习了规范化,目前我正在开发一个使用 SQLite 作为后端数据库的多人游戏。
关于它的一些信息:
简化后的结构如下所示:
player_id | level | exp | money | inventory
---------------------------------------------------------
1 | 3 | 120 | 400 | item a; item b; item c
好的。如您所见,我在“库存”列中以字符串形式存储了一个表/数组。这是违反规范化的。
但问题是:为玩家的库存制作额外的桌子对我来说只会带来不利影响!
我访问数据库的唯一点是: 当玩家加入游戏并加载其个人资料时 保存玩家资料时当玩家加入时,我从数据库中加载他的数据并将其存储在内存中。保存播放器时,我仅每五分钟写入一次数据库。所以我的脚本中实际上很少有 SQL 查询。
如果我为库存使用额外的表格,我将不得不在加载时:
执行性能查询,可能更多的数据密集型查询,以从属于玩家 X 的库存表中获取所有项目 遍历结果并将其转换为表格以存储在内存中保存后:
从库存表中删除属于玩家 X 的所有物品(玩家可能已经丢弃/出售了一些物品?) 遍历表格并查询玩家拥有的每个物品如果我将所有玩家数据保存在一张表中:
我只有一个用于保存和加载的查询 一切都在一个地方 我只需要在加载和保存时在我的脚本中(反)序列化表格我现在该怎么办?
我的论点和情况是否有理由反对规范化?
【问题讨论】:
还要考虑的是inventory
列的数据类型。显然,通过您的方法,您将获得各种长度的字符串,并且您需要确保字符串值在它们变得太长时不会被截断。为了安全起见,您最终可能会得到 text
或 varchar
之类的数据类型(即长度不受限制),我不确定这是一个最佳决策,从性能角度来看。
如果稍后您想知道哪个玩家拥有某件物品怎么办?喜欢独特的物品或强大的物品?另外,如果物品可以升级、附魔、损坏或具有其他属性怎么办?
也许这个链接会对你有所帮助 - en.wikipedia.org/wiki/Denormalization
【参考方案1】:
您使用任何技术的原因都是为了利用该技术的优势。 SQL 有许多您似乎不想使用的优点,如果您不需要它们也没关系。在尼尔斯蒂芬森的十二生肖中,主角提到从五金店购买的东西很少用于其预期目的。软件也是这样。重要的是它有效,几乎 100% 的时间有效,而且运行速度足够快。
然而,我不禁想到,总有一天你会发布一些强大的项目到野外,你会想要在数据库层处理这个问题。假设您不小心送出了一些超级杀戮巨剑库存物品,这些物品会在使用时杀死 50 米内的所有物品(包括持用者),并且您想将这些物品从游戏中移除。作为对失去超级杀戮超级死亡剑物品的人的道歉,你想为你拿走的每把超级杀戮超级死亡剑给他们 100 钱。
使用适当规范化的数据库结构,这是一项微不足道的任务。使用非规范化结构,它会变得更加困难和缓慢。规范化的数据库也将在未来更容易扩展设计。
那么你确定你不想标准化你的数据库吗?
【讨论】:
【参考方案2】:我的论点和情况是否合理 反对规范化?
不是基于我目前所看到的。
通用引擎中的规范化数据库设计(适当索引并通过 UPSERTS、事务等有效使用数据库)通常会优于代码,除非代码进行了非常严格的优化。通常在此类代码中,通用 RDBMS 引擎的某些功能被放弃,例如 ACID 属性或引用完整性之一。
如果您想要非常简单的数据访问(您吹捧一个表,一个查询作为好处),也许您应该查看以文档为中心的数据库,例如 mongodb 或 couchdb。
【讨论】:
【参考方案3】:过早优化的另一种情况。
您正在尝试优化您没有任何性能指标的东西。目标平台是什么?即使是当今最糟糕的计算机每秒也可以运行至少数百次阅读操作。然后你为更多用户添加更好的硬件,然后你可以去云,当你遇到谷歌、Twitter和Facebook正在处理的问题时,你可以考虑去规范化。即便如此,最好的解决方案还是某种键值数据库。
也许您应该查看Database Normalization 上的***文章,以提醒您为什么规范化数据库是一件好事。
【讨论】:
【参考方案4】:您还应该考虑这些项目。项目是否对每个用户都是唯一的,或者 user1 是否可以拥有 item1 而 user2 是否拥有 item1。如果您现在要更改 item1,则必须检查整个表并检查哪个用户拥有此项目。如果您要规范化您的表格,这会容易得多。
但到此为止,我认为答案是:视情况而定
【讨论】:
【参考方案5】:有很多可能的答案,但适合您的答案是可以选择的。请记住,您的选择可能需要随着时间的推移而改变。
如果您需要保留的数据量很小(即:适合单个表行)并且您只需要不经常更新该数据,并且您没有任何理由关心该数据的子集,那么你的方法是有道理的。随着时间的推移,你的玩家获得了更多的物品,你为游戏添加了更多的个性化,你可能会开始挑战 SQLite 的限制,你需要改进你的设计。如果您发现您需要能够查询物品列表来确定哪些玩家拥有哪些物品,那么您需要改进您的设计。
通常认为尽早制定正确的数据架构是个好主意,但今天开会试图猜测 5 到 10 年后您将如何使用您的软件是没有意义的。最好得到一个能满足今年需求的设计,然后计划在一年后重新评估设计。
【讨论】:
【参考方案6】:不,您的论点无效。他们基本上归结为“我想在我的客户端代码中而不是在 SQL 中进行所有这些处理,然后将它们全部写入单个字段”,因为您仍在进行所有 完全相同的处理 生成字符串。通过这样做,您将无法轻松加载列表的一小部分并失去与实际 item
表的关系,该表可能包含有关项目的更多信息(我假设您是基于名称而不是使用内部项目 ID,这是一个非常糟糕的主意,imo)。
不要这样做。从长远来看,随着您需求的发展,您希望采用的方法会为您带来更多的工作。
【讨论】:
【参考方案7】:当你的库存中有十万件物品而你只想带回两件时会发生什么?
如果这是您为一次性课程拼凑起来的东西,并且您再也不会使用,那么是的,快速而肮脏的路线可能是您更快的选择。
但是,如果您要为此工作几个月,那么您将在该设计决策中遇到长期问题。
【讨论】:
RE:What's going to happen when you have one hundred thousand items in your inventory and you only want to bring back two?
我猜单个玩家在任何时候都只会有几样东西。【参考方案8】:
您是说您认为从“库存”中解析字符串不需要花费任何时间或精力吗?因为从子表中存储/检索库存项目所需的一切都是您需要使用此字符串执行的操作,并且您没有任何数据库工具可以帮助您执行此操作。
此外,如果您有一个单独的库存项目子表,您可以实时添加和删除项目,这意味着如果应用程序崩溃或用户断开连接,他们不会丢失任何东西。
【讨论】:
@R ***s 为什么您需要删除所有项目,而不是只跟踪已更改的内容? 网络上一些最大和最繁忙的网站(包括这个)通过从几个规范化表中获取信息并将信息放回规范化表来响应每个页面请求。你认为你的应用比 ***、eBay 或 Slashdot 更复杂吗? 我打算写一个与保罗类似的答案。您完全省略了与来回将字符串解析为数组相关的工作。即使它是 1-liner(例如,当您的语言支持“eval”时)并且看起来不像,它也会消耗时间!此外,我认为您误解了保罗对实时一词的使用。最后:难道您没有看到使用标准化数据库操作库存是多么容易吗? (相对于现在有多难——考虑到大项目) 看,仅仅因为你害怕做数据库的东西并不意味着它不是正确的解决方案。首先,您不是“对每个元素进行查询”——您是在创建一个语句,并为每个项目执行一次。这就像一个循环中的 3 个语句。 @R ***s:您是否运行了一些性能测试来实际查看 SQLite 数据库在删除或向表中插入多列时的执行情况?这也可能根本不是(性能)问题。如果您还没有进行一些分析,您可能会遇到过早优化的危险,从而最终得到一个次优的数据库模型。以上是关于在这个数据库中不使用规范化表是否很糟糕?的主要内容,如果未能解决你的问题,请参考以下文章
将图像作为数据 URI 存储在数据库 BLOB 中是否很糟糕?