SQL:如何为我的数据结构设计最佳表

时间:2014-11-05 11:12:59

标签: sql postgresql database-design

我正在为在线纸牌游戏设计postgresql数据库。我想为用户提供访问其播放历史记录的选项 - 用户可以查看他的游戏日志。

我要保存的数据具有以下结构:

Player Ids | game_data
-----------|--------------
A,B,C,D    | ..game log..
A,D,E,F    | ..game log..
D,C,A      | ..game log..
D,A        | ..game log..

每个游戏最多可以有22个参与者,因此最多玩家数为22,最小玩家数为2。

到目前为止,我有大约100M的记录。我每天都会添加大约500K的记录。我有大约500K玩家。 Player-ID是一个32字节的字符串(MD5)。

我希望玩家能够访问他们的game_data,所以我希望玩家能够通过Player-Id选择最后的XX games_logs。我需要尽快做到这一点。 Postgres最好的方法是什么?我宁愿将所有这些数据保存在一个表中。

到目前为止,我正在考虑两种方法:

方法1

创建一个JSON类型的字段并将所有播放器保存在JSON-Array中并在SELCT语句中查询JSON。

方法2

为每个玩家在一个表中创建22个字段(如果没有玩家字段为NULL)并对所有字段进行丑陋的查询。

到目前为止,我不喜欢这些方法中的任何一种。如果有更好的方法吗?

典型的请求是:为PLAYER_ID选择最后的XXX游戏=' A'

3 个答案:

答案 0 :(得分:2)

用户可以拥有多个密钥,密钥可能属于许多用户,这就是为什么您应该让第三个表包含用户密钥对的原因。你应该键入密钥表中每个密钥的json值。

应该是这样的。

enter image description here

答案 1 :(得分:0)

我会使用一个带有串行字段的表(只是为了遵循约定),一个用于存储键的整数数组和一个用于保存数据的json字段。

您可以在PostgreSQL中向数组列添加索引。

答案 2 :(得分:0)

你真的会后悔2号方法。在检索每个用户的GameData时,检查每个USER1 ... 22字段的playerid = X是完全可能的。我已经看到它在设计用于简单数据输入的系统中多次使用,而很少考虑将数据输出。您的SQL或其他代码将是脆弱的,您将厌恶编写测试代码。

你真的需要把它放在一张桌子上吗?标准('规范化')通过适当的数据库索引和调优,多对多方法可以非常快。尽可能使用整数键。调用该选项#3(例如,使用两列user_id和game_id制作多对多表GameUsers表)

我有类似的情况,并且同时做#1和多对多表。对于您的解决方案#1,我在文本字段中插入了用户名的分隔列表,而不是JSON。我只是将这些user_id(在我的情况下是文本,我也不喜欢)存储为逗号分隔(我的客户喜欢逗号)但是我添加了这样的前后结尾逗号:"中,A,d,E,F,"

简单SQL:

select game_log from game_data where user_list LIKE ('%,D,%')

或者如果user_id是变量或列

select game_log from game_data where user_list LIKE ('%,' || user_id || ',%')

您需要两个分隔符,因为用户名可以重叠(例如" Mirko"和#34; Mirkota")并且您不必浪费时间检查其&#39的情况;在列表的开头或结尾。当然,您必须使用用户ID中不允许的分隔符,并确保从用户输入数据中去除此分隔符(以及其他禁用字符)以避免SQL注入。

同时做两件事的重大缺点是保持它们同步但是在多对多表(方法#3)中给出数据,你可以使用string_agg(expression, delimiter)重新生成用户列表并连接额外的分隔符

我不认为Serial或" array"即使使用位置索引,字段在这里也无济于事。您仍然需要搜索数组中的每个位置,并且绝大多数22个长度数组将大部分为空。

在我的情况下,我正在进行社交网络分析,因此我需要知道用户何时在一起并且使用多个LIKE条件比多个连接更快。