我正在使用PHP& amp;来实现一个游戏化平台MySQL的。人们可以通过几个动作获得经验值(测验,完成其个人资料,转到一个页面......)
我有一个名为members
的表,我存储了用户的个人资料。包括level_id
:
CREATE TABLE members (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(250) NOT NULL,
`level_id` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `level_id` (`level_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我有一个名为points
的表,每次用户获得经验值(XP)时都会有一个注册表。
CREATE TABLE points (
`id_member` int(10) unsigned NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`points` int(11) NOT NULL,
KEY `id_member` (`id_member`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我有另一张名为levels
的桌子,在那里我录制了关卡系统:
CREATE TABLE levels (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(250) NOT NULL,
`experience_needed` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
每次将记录插入points
表时,我都会计算新的用户级别,在experience_needed
表中查找正确的levels
。
然后我使用members
字段将用户级别保持在level_id
表中。
现在我问这是否是最好的方法。其他替代方案是:
level_id
的视图答案 0 :(得分:1)
你是对的level_id
并非绝对必要,完全规范化的架构不会包含它。
您基本上是在缓存level_id
以使阅读更容易,这可能会有所不同,具体取决于您的应用程序。如果读取/显示用户的级别的次数比授予的次数要多得多,并且每个成员可以有很多points
个记录,那么阅读的性能和简单性可能是值得的。成本是每个用户行的少量存储,对points
的写入影响很小,以及使level_id
与points
中的数据保持同步的复杂性增加。
最后一个是非规范化的主要缺点:它违反了Single Source of Truth规则,为导致数据不一致的错误打开了大门。
其他一些观察结果:
level_id
值得存储在members
中,那么总经验值也可以。如果您缓存level_id
但仍需要每次都读取所有points
条记录以获得总数,那么您将获得两个世界中最差的记录。当然,这取决于您的应用程序。points
中是个好主意,但它并没有告诉你太多。我可能会将其命名为achievements
或point_events
,并存储有关获得积分的原因的一些信息。 points
而在其他地方使用experience_needed
并不理想。我会选择一个名字并在任何地方坚持使用它:experience
或points
或xp_points
或wahtever。 最后:你想要在数据库设计(和数据建模,应该首先)上做得更好,但是你是否存储或计算level_id
可能不会直到/除非你的系统非常庞大且性能受限,否则问题太多了。所以在这一点上不要太担心。立即构建,稍后进行优化。