我对我的MySQL数据库提出了一个问题,并希望获得最有效的信息。
我的问题如下,
我正在为我的棋盘游戏网站开发高级功能。一个高级功能是用户所玩的所有游戏将“永久”存储(以供用户随后查找)。对于普通用户,将删除超过18个月的游戏。
现在我需要找出一种有效的方法来删除普通非高级用户的游戏(超过18个月)并为高级用户保留游戏。
简化事情我得到了两张桌子(实际上还有一张桌子可以存储每场比赛的游戏参与者):
游戏,
id=INT
play_date=DATETIME
end_score=INT
player_id_1=INT
player_id_2=INT
用户,
id=INT
premium=BOOLEAN (true=enabled, false=not enabled)
用户表包含300.000+行,而Games表包含几百万行。每天约有20,000场比赛 被添加到游戏桌中。
从非高级用户中删除超过18个月的游戏的最有效方法是什么。
到目前为止,我们已经为每个星期一早上的所有用户删除了超过18个月的游戏。
现在我需要考虑高价值和游戏日期。
一些解决方案(?):
欢迎任何提示......
答案 0 :(得分:3)
使用过期日期和索引。
在该列上允许NULL。
高级用户的游戏将为NULL。
使用expire_date<删除游戏sysdate将使用索引,它是一个INDEX RANGE SCAN(它必须是可订购索引,我的意思是,某种B树内部表示......但我不是MySQL的专家)。
修改强>
或者使用expire_date保存一个单独的注册表PK表。因此,高级用户记录不会占用太多空间。然后你从xxx中删除pk in(从expiring_table中选择pk)。
但这并不比以前的解决方案有很好的改进。
<强>年龄强>
也许你可以使用年龄(例如1岁= 1个月)。并在表格中设置字段“month_to_live”。对于非空的所有记录,每月更新字段+ = 1。那使用了相等过滤器。但正如我之前所说,我不是专家,所以我不知道你可以从中获得多少优化。)
我应该坚持使用expire_date字段(并且您有额外的功能可以将实时期限单独扩展到任何人,而不会在删除记录时产生额外的开销)。
答案 1 :(得分:1)
下载数据库转储并在您的计算机上进行基准测试。这应该可以让您很好地了解各种解决方案的性能
除此之外,这是对这些SQL查询问题的通常回复:对查询运行“解释”并确保您拥有正确的索引。
答案 2 :(得分:0)
加入不应该太糟糕,我猜你是不是在做那个“直播”的查询? 另一种选择是在显示游戏时进行查询:如果用户是高级用户,则不限制,否则限制范围。
答案 3 :(得分:0)
每次用户更改状态时,您都需要避免使用更新游戏表的解决方案,因为这是不必要且缓慢的。
这是一个。假设您每天都在同一时间运行查询:
DELETE games FROM games
JOIN users u1 ON (u1.id=games.player1_id AND NOT u1.premium)
JOIN users u2 ON (u1.id=games.player2_id AND NOT u2.premium)
WHERE games.play_date BETWEEN DATE_SUB( now(), INTERVAL 18 MONTH 1 DAY 1 HOUR)
AND DATE_SUB( now(), INTERVAL 18 MONTH )
当然你应该有一个游戏索引(play_date)。
这里的想法是日期范围检查仅检查可能需要删除的游戏,并且尚未经过昨天的查询检查。一种“滚动窗口”。
相反,这个:
WHERE games.play_date < DATE_SUB( now(), INTERVAL 18 MONTH )
每次都会检查表中所有现有的游戏,并且速度会慢得多。