展览
假设我们的系统有用户和一些游戏。我们把这些游戏称为A、B和C。
为了简单起见,我们的初始表格如下所示:
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS games (
id SERIAL PRIMARY KEY
);
问题
每当我们玩这些游戏并完成它们时,我们都必须记录与特定用户的游戏相关的统计数据。例如,对于游戏A,我们必须记录total_jumps和total_crouches,因为游戏的机制允许这种累积,但是游戏B和C可能要求我们记录其他total_*字段(尽管前缀total_不是必需的)。我该如何存储这些信息?
我对这个问题的解决方案感到困扰。我想出了两种方法:
解决方案 1
有一张表用于此:
CREATE TABLE IF NOT EXISTS statistics (
user_id SERIAL REFERENCES users (id) ON DELETE CASCADE,
game_id SERIAL REFERENCES games (id) ON DELETE CASCADE,
fields JSONB,
PRIMARY KEY (user_id, game_id)
);
这样,我们就可以将来自字段列的任意数据解析到应用程序级别。
解决方案 2
有多个桌子,每个游戏一个:
CREATE TABLE IF NOT EXISTS A_statistics (
user_id SERIAL PRIMARY KEY REFERENCES users (id) ON DELETE CASCADE,
total_jumps INTEGER,
total_crouches INTEGER
);
就我个人而言,解决方案 #2 看起来更好,但是...这个问题仍然困扰着我。好像我错过了什么,因为这两个选项都不能使扩展(添加新游戏)变得更容易?假设我们添加游戏D、E和F。这两种解决方案都要求我们以某种方式处理这些游戏所需的特定字段(在应用程序级别)。这是我必须接受的事情吗?或者是否有第三个更好的解决方案,我只是没有看到?
您可以使用非关系型数据库来存储此类数据。例如,在 mongoDB 中,您可以有一个游戏集合。然后在您的应用程序代码中,您可能有多个数据模型:
足球比赛总传球次数
BoxingGame 总拳击数
这些数据模型中的每一个都将保存到同一个集合中,这是由于使用非关系数据库而成为可能的。
此外,这些数据模型中的每一个都可以从具有一些共同属性的基本游戏模型继承。
每个数据模型都会存储某种表示游戏的鉴别器。这是必需的,以便您的应用程序代码知道如何从数据库加载已保存的游戏,即保存的文档对应于哪个数据模型。请参阅https://mongoosejs.com/docs/discriminators.html#discriminators
关系数据库管理系统需要定义明确的数据结构 - 即名称中的“关系”。因此,拥有运行时变量需求是一个众所周知的难题。
尽管如此,最新版本的 Everything 都能很好地处理 JSON。在 SQL 查询中进行一些 JSON 解析不会对性能造成太大影响。
从单个 JSON 列开始即可开始使用。随着时间的推移,您会发现许多查询读取相同的指标,或者某些游戏非常受欢迎。专门为这些查询添加一列,并将值写入该列和 JSON。换句话说,从 1 开始,随着时间的推移移动到 2。
如果你研究得足够久,你就会读到关于“实体属性值”模型的内容。它在小规模下运行良好(取决于硬件),但根据我的经验,一旦规模不再小,它就会变得非常糟糕。