这是我一直想知道的事情,并且还没有看到真正的(好的)解决方案。这是一个我想象很多游戏的问题,我不能轻易想到如何解决(好)。我们欢迎您的想法,但由于这不是一个具体的问题,所以不要再询问更多细节了 - 只需要补充它们! (并解释你的构成)。
好吧,所以,很多游戏都有(库存)物品的概念,而且往往有数百种不同的物品,所有物品的数据结构都非常不同 - 有些物品非常简单(“摇滚”),其他人可能有疯狂的复杂性或背后的数据(“一本书”,“一个编程的计算机芯片”,“一个有更多项目的容器”)等。
现在,编写类似的东西很简单 - 只需让所有东西都实现一个接口,或者扩展一个抽象的根项。由于编程世界中的对象在内部和外部看起来不一样,所以任何类型的项目都有多少和哪种私有字段都没有问题。
但是当谈到数据库序列化时(二进制序列化当然没有问题),你面临着一个两难的境地:你会如何在典型的SQL数据库中代表它?
我已经看过一些解决方案的尝试,但我觉得这些解决方案都不令人满意:
项目的二进制序列化,数据库只保存一个ID和一个blob。
每种商品类型的表格。
一个包含许多字段的表,每个项目都没有使用。
一些带有一些“基本配置文件”的表用于存储,其中类似的项目被抛在一起并对不同的数据使用相同的字段。
你有什么想法?您是否看到过另一种效果更好或更差的设计?
答案 0 :(得分:4)
这取决于您是否需要对这些属性进行排序,过滤,计数或分析。
如果你使用EAV,那么你会很好地搞砸自己。尝试对EAV架构进行报告。
最好的选择是使用表继承:
PRODUCT
id pk
type
att1
PRODUCT_X
id pk fk PRODUCT
att2
att3
PRODUCT_Y
id pk fk PRODUCT
att4
att 5
对于不需要搜索/排序/分析的属性,请使用blob或xml
答案 1 :(得分:2)
我有两种选择:
基本类型的一个表和专用类型的每个“类”的补充表。
在此架构中,所有“对象”共有的属性存储在一个表中,因此您可以为游戏中的每个对象创建唯一的记录。对于书籍,容器,可用物品等特殊类型,您可以为这些项目所需的每个唯一属性或关系设置另一个表。因此,每个特殊类型将由两个记录表示:基础对象记录和特定特殊类型表中的补充记录。
PROS:您可以使用数据库的基于列的功能,如自定义域,检查和xml处理;你可以在某些类型上使用更简单的触发器;你的问题在不同的问题上完全不同。
缺点:对于许多对象,您需要两个插入。
对特殊类型数据使用“kind”枚举字段和类似JSONB的字段。
这有点像#1或#3,除了一些数据库帮助。 Postgres添加了JSONB,让您对旧的EAV模式有所改进。其他数据库具有类似的复杂字段类型。在此策略中,您将滚动自己的迷你架构,并将其隐藏在JSONB字段中。 kind字段声明了您希望在该JSONB字段中找到的内容。
PROS:您可以在查询中提取特殊类型的数据;可以添加检查约束并有一个简单的模式来处理;即使您的数据是异质的,您也可以从索引中受益;您的查询和插入很简单。
缺点:类似JSONB的字段中的数据类型非常有限,您必须进行自己的验证。
答案 2 :(得分:1)
是的,设计像这样的数据库格式是一件痛苦的事。我正在设计一个通知系统,并遇到了同样的问题。然而,我的通知系统不像你的那么复杂 - 它拥有的数据最多是id和用户名。我目前的解决方案是1和3的混合 - 我序列化与每个通知不同的数据,并使用列用于2个用户名(有些可能有2或1)。我回避方法2,因为我讨厌那种设计,但它可能只是我。
然而,如果你能负担得起,我建议在RDBMS范围之外思考 - 听起来像非RDBMS(特别是键/值存储的)可能更适合存储这些数据,特别是如果项目1和第2项与每个项目的区别很大。
答案 3 :(得分:1)
我确信此前已经有一百万次问过这个问题了,但除了你在问题中讨论过的选项之外,你可以看一下非常灵活的EAV架构,但它有自己的一套缺点。
另一种替代方案是不是关系的数据库系统。有对象数据库以及各种键/值存储和文档数据库。
通常,当您需要查询灵活属性时,所有这些事情都会在某种程度上分解。然而,这是一种内在问题。从概念上讲,准确查询非结构化的东西真正意味着什么呢?
答案 4 :(得分:1)
首先,您实际上需要真实数据库的并发性,可伸缩性和ACID事务吗?除非您正在构建MMO,否则您的游戏结构可能会适合内存,因此您可以直接搜索并以其他方式操作它们。在这种情况下,“数据库”只是序列化对象的存储,您可以将其替换为文件系统。
如果你得出结论(需要一个数据库),那么关键在于从数据管理的角度来看出"atomicity"对的意义。
例如,如果游戏项具有一堆属性,但这些属性都不是在数据库级别单独操作的(即使它们很可能处于应用程序级别),那么它可以被视为“原子”从数据管理的角度来看。 OTOH,如果需要在某些属性上搜索项目,那么你需要一种很好的方法来在数据库中对它们进行索引,这通常意味着它们必须是单独的字段。
一旦你确定了应该是“可见的”属性而不是从数据库角度来看应该是“不可见”的属性,将后者序列化为BLOB(或其他),然后忘记它们并集中精力构建前者。 / p>
这就是乐趣开始的地方,你可能需要使用“以上所有”策略来获得合理的结果。
BTW,一些数据库支持可以进入异构数据结构的“深层”索引。例如,看看Oracle的XMLIndex,虽然我怀疑你会在游戏中使用Oracle。答案 5 :(得分:1)
您似乎正在尝试为游戏环境解决此问题,因此您可以考虑采用基于组件的方法。 我不得不说我个人还没有尝试过这个,但我已经研究了一段时间,在我看来可能会有类似的东西。
想法是游戏中的所有实体基本上都是一包组件。例如,这些组件可以是Position
,Energy
或您的广告资源案例Collectable
。然后,对于此Collectable
组件,您可以添加自定义字段,例如category,numItems等。
当您要渲染广告资源时,您只需在实体系统中查询具有Collectable
组件的项目。
如何将其保存到数据库中?您可以在它们自己的表中单独定义组件,然后为实体(每个也在它们自己的表中)定义组件,您可以添加一个“组件”列,该列将包含引用这些组件的ID数组。这些ID实际上就像外键一样,但我知道这并不是你如何在关系数据库中建模,但你明白了。
然后,当您在运行时加载实体及其组件时,基于正在加载的组件,您可以在其组件包中设置相应的标志,以便您知道此实体具有哪些组件,然后它们将变为可查询
Here是关于基于组件的实体系统的有趣读物。