php-存储图形数据的最有效方法
作者:互联网
我总共提出了三种不同的,同样可行的方法来保存图形数据.
所讨论的图表是“随时间推移在各个类别中的玩家得分”.类别包括“建筑物”,“项目”,“任务完成”,“成就”等.
方法1:
CREATE TABLE `graphdata` (
`userid` INT UNSIGNED NOT NULL,
`date` DATE NOT NULL,
`category` ENUM('buildings','items',...) NOT NULL,
`score` FLOAT UNSIGNED NOT NULL,
PRIMARY KEY (`userid`, `date`, `category`),
INDEX `userid` (`userid`),
INDEX `date` (`date`)
) ENGINE=InnoDB
该表针对每个用户/日期/类别组合包含一行.要显示用户数据,请按用户ID选择.旧条目通过以下方式清除:
DELETE FROM `graphdata` WHERE `date` < DATE_ADD(NOW(),INTERVAL -1 WEEK)
方法2:
CREATE TABLE `graphdata` (
`userid` INT UNSIGNED NOT NULL,
`buildings-1day` FLOAT UNSIGNED NOT NULL,
`buildings-2day` FLOAT UNSIGNED NOT NULL,
... (and so on for each category up to `-7day`
PRIMARY KEY (`userid`)
)
由于是主键,因此按用户ID选择的速度更快.每天得分都在字段中向下移动,如下所示:
... SET `buildings-3day`=`buildings-2day`, `buildings-2day`=`buildings-1day`...
条目不会被删除(除非用户删除其帐户).可以使用INSERT … ON DUPLICATE KEY UPDATE查询添加/更新行.
方法3:
为每个用户使用一个文件,其中包含其分数数据的JSON编码数组.由于无论如何都是通过AJAX JSON调用获取数据的,因此这意味着可以静态获取文件(甚至缓存到下一个午夜),而不会对服务器造成任何压力.服务器每天都要运行每个文件,shift()会将每个数组的最旧记录除掉,最后将push()的新数组推入.
我个人认为方法3到目前为止是最好的,但是我听说过使用文件而不是数据库的不好的事情-例如,如果我希望能够根据用户在不同类别中的得分来对其进行排名,那么该解决方案将非常糟糕.
在这两种数据库解决方案中,我已经在一个较旧的项目中实现了方法2,这似乎工作得很好.方法1似乎“更好”,因为它更好地利用了关系数据库和所有这些东西,但是我有点担心它会包含(用户数量)*(类别数量)* 7行,出来是一个很大的数字.
我缺少什么可以帮助我最终决定使用哪种方法的东西吗? 1、2、3还是以上都不是?
解决方法:
如果要使用关系数据库,则方法1比方法2更好.它经过规范化,因此易于维护和搜索.我将date字段更改为时间戳,并将其称为add_on(或诸如“ date”之类的非保留字).并且我要添加一个auto_increment主键score_id,以便user_id / date / category不必唯一.这样,如果用户设法在同一秒内将其建筑得分增加两次,则两者仍将被记录.
第二种方法要求您每天更新所有记录.第一种方法仅执行插入操作,不执行任何更新,因此每个记录仅写入一次.
… SET
buildings-3day
=buildings-2day
,buildings-2day
=buildings-1day
…
您是否真的想每天更新表中的每个记录,直到时间结束?!
Selecting by user id is faster due to being a primary key
由于user_id是您的Method 1主键中的第一个字段,因此查找起来同样会很快.作为常规索引的第一个字段(这是我上面建议的),它仍然会非常快.
关系数据库的想法是,每一行代表一个实例/动作/事件.因此,当用户做某件事以影响其分数时,请执行INSERT记录其所作的事情.您始终可以根据这样的数据创建摘要.但是您不能从摘要中获得此类数据.
其次,您似乎毫无疑问地担心摆脱旧数据.为什么?您选择的查询的日期范围将自动排除旧数据.而且,如果您担心性能,可以根据行龄来设置表partition,或者设置cronjob定期删除旧记录.
预计到达时间:关于文件中存储的JSON
在我看来,这将方法2的缺点(难以搜索,每个文件必须每天更新)与文件访问的其他缺点结合在一起.文件访问很昂贵.文件写入更是如此.如果您确实要存储摘要数据,则仅在请求数据时才运行查询,并将结果按user_id存储在摘要表中.该表可以包含一个JSON字符串:
CREATE TABLE score_summaries(
user_id INT unsigned NOT NULL PRIMARY KEY,
gen_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
json_data TEXT NOT NULL DEFAULT '{}'
);
例如:
鲍勃(user_id = 7)首次登录游戏.他在个人资料页面上,显示他的每周统计信息.这些查询已运行:
SELECT json_data FROM score_summaries
WHERE user_id=7
AND gen_date > DATE_SUB(CURDATE() INTERVAL 1 DAY);
//returns nothing so generate summary record
SELECT DATE(added_on), category, SUM(score)
FROM scores WHERE user_id=7 AND added_on < CURDATE() AND > DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
GROUP BY DATE(added_on), category; //never include today's data, encode as json with php
INSERT INTO score_summaries(user_id, json_data)
VALUES(7, '$json') //from PHP, in this case $json == NULL
ON DUPLICATE KEY UPDATE json_data=VALUES(json_data)
//use $json for presentation too
今天的分数是根据需要生成的,不会存储在摘要中.如果Bob今天再次查看自己的分数,则历史分数可以来自摘要表,也可以存储在第一个请求后的会话中.如果Bob一周都不来,则无需生成摘要.
标签:data-storage,graph,mysql,php 来源: https://codeday.me/bug/20191101/1982403.html