【问题标题】:Mysql leaderboard with heavy use使用量大的Mysql排行榜
【发布时间】:2015-04-18 12:33:12
【问题描述】:

我有一堆将数据发送到 mysql 服务器的移动应用程序。每个应用程序都有自己的表,它可以在短短几周内轻松达到 100,000 多条记录。我目前每天大约有 1000 万次调用数据库。我的系统当前设置的方式是每 5 分钟一个 cron 将为每个表运行一堆查询并将 html 缓存到一个文件中。然后,当用户调用排行榜时,我运行 1 个查询来获取他们当前的排名,然后我显示缓存的 html 以及我从查询中提取的排名。

虽然这可行,但我希望更改它有两个主要原因。我想在客户端而不是在我的服务器上提供排行榜。我想发送 json 然后在他们的设备上解析它。我还想为每个应用添加每日、每周、每月和所有时间的排行榜。目前我存储数据的方式不允许这样做。

我的问题是

  1. 将 json 发送给用户的最佳方式是什么?像我在文件中处理 html 一样缓存 json 然后让用户调用该文件是否明智?对此唯一的抱怨是我需要为每个应用程序(每天、每周、每月、所有时间)创建 4 个 json 文件。

  2. 如果想要添加每日、每周、每月和所有时间的分数,数据库结构会是什么样子?我已经为我的一些应用程序添加了每日分数,但我停止了这样做,因为这似乎是一种糟糕的做法。我基本上保留了所有用户的大列表以及他们开始一天的工作,每次他们更新他们的分数时,我都会将其与他们存储的分数进行比较并得到差异。该表对于每日而言很快就变得非常大,如果我每周和每月都有数百万条记录,那将很容易。

我每个应用的表结构真的很简单

CREATE TABLE `app_test1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `deviceID` varchar(50) NOT NULL,
  `username` varchar(25) NOT NULL,
  `score` int(11) unsigned NOT NULL
  PRIMARY KEY (`id`),
  UNIQUE KEY `deviceID_2` (`deviceID`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

通常我会进行更改并在我认为合适的情况下对其进行调整,但是有这么多调用我发现很多次一个简单的小更改很容易使服务器崩溃所以现在我喜欢在我之前获得想法甚至尝试任何事情。

【问题讨论】:

  • 另外我想知道将用户排名存储在数据库中然后运行 ​​cron 每隔几分钟更新一次排名是否明智?
  • 为了限制所涉及的数据量,我建议对表进行规范化,以便将 deviceID 和用户名存储在其他地方,而不是使用 varchar(50) 和 varchar(25) 你有 2 (较小的)整数。想一想,您可能可以将用户名和设备合并到一个外部表中;这样,您就可以从 varchar(75) 转到单个 int,从而严重减少使用的表空间和索引空间。因此更少的 I/O 和改进的缓存(更多的数据适合相同数量的 ram)。
  • 在我们运行和过早优化之前——您每秒有多少查询? 5 分钟 cron 作业中的查询需要多长时间?分数有变化吗?那就是用户设备到昨天的总点数会保持不变吗?而你只需要在重新计算排名之前添加今天的积分?
  • @deroby 我如何将 deviceID 保存在不同的表中,它是该表中的唯一键。将用户名存储在不同的表中是否有意义?现在我每个应用程序都有一个表,因为我发现它运行得更快,因为表更小。如果我将所有用户名存储在他们自己的表中,那么该表很容易增长到数百万。这样做会更好吗,并且必须查询具有数百万条记录的表?
  • 哎呀,你确实在deviceID上放了一个UQ,对不起,没注意到。这让我关于标准化的观点变得毫无意义,对此感到抱歉。再说一次,仔细看看我不确定我是否完全理解CREATE TABLE 的语法,KEY 'score' ('score', 'appname') 是做什么的? (看起来appname 还不是表格的一部分(还)?你在桌子上得到了很多插入,DeviceID 可能会陆续出现吗?如果是这样,我会摆脱@987654327 @autonumber 并使用deviceID 作为PK。但是如果它随机进入会导致碎片=(

标签: mysql query-optimization leaderboard


【解决方案1】:

1) 不管最好的方法是缓存 JSON 文件,它确实具有与您在 HTML 中缓存的数据保持一致的好处。生成该 JSON 可能会重用您在 HTML 中使用 (d) 的相同代码,因此在某种程度上对您来说工作量更少。

2) 这部分很简单,至少乍一看是这样:为您为用户注册的每个分数添加一个时间戳。 确保添加包含时间戳的索引(或更多):您将根据时间执行大量数据操作。

另一种可能性是为每日、每周、每月和所有时间的分数提供新表格。缺点是这会增加服务器端代码的复杂性,坦率地说,这有点令人作呕……但是,您只需要在特定表上查询相关的高分即可。因此,如果您保留 50 个最高分,那么这些表中将只有 50 x your number of apps 行。当用户注册一个新分数时,您检查它是否高于 50 中的最低每日分数:在这种情况下,将其插入表中并删除最低分数。如果它超过每日分数,请检查每周分数,如果它超过每周检查每月等等。当您插入新的高分时,重新创建缓存的高分文件(HTML 或 JSON)。运行 cron 以在一天结束时清理每日表等。对这些表的读取和写入将比全表搜索更快。

只是给你一些想法,我希望我有意义。

编辑:我忘记了另一种可能性,即将您的数据拆分到不同的服务器之间。例如,在服务器 1 上拥有游戏 A、B 和 C 的数据,在服务器 2 上拥有游戏 D、E、F 和 G 的数据。这将使您能够更均匀地处理负载。这需要一些麻烦(您不希望服务器接收 80% 的流量,而另一台只获得剩余的 20%),但这是一个易于实施的解决方案,因为所有游戏似乎都使用相同的模式;缺点是维护两台服务器的成本显然更高。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 2018-01-31
    • 2013-08-31
    • 2013-12-02
    • 2015-01-29
    • 2021-12-15
    • 2016-03-18
    相关资源
    最近更新 更多