【问题标题】:AJAX - MySQL Query Flooding ServerAJAX - MySQL 查询泛洪服务器
【发布时间】:2020-04-26 22:14:10
【问题描述】:

我在这几天一直在尝试不同的方法来减少由于最近的 AJAX 脚本导致的 95-135% 的 CPU 负载,调用此查询:

SELECT COUNT(*) as total FROM users WHERE last_access >= DATE_SUB(NOW(), INTERVAL 1 MINUTE) ORDER BY last_access DESC LIMIT 16

我已经尝试COUNT(id) 来减少表扫描时间,我添加了LIMITORDER BY,我认为它有所改善,但我不知道。我在我的 BSD 机器上监控 top -P,CPU 一直在飙升,几乎要杀死 apache,同时依靠它来进行查询测试。

我们有一个查询 AJAX 脚本的 jquery 位,并根据在 jquery 端以 15 秒的间隔(查询语句为 1 分钟)根据最后在线用户返回表计数。一天还好,然后注意到服务器超时运行,粉丝们陷入了混乱。

我们最终删除了 MySQL 5.7 并安装了 MariaDB 12.4 - 这带来了巨大的变化,但是当它的负载降低了 ~20% CPU 时,它也在挣扎......所以查询是坏的。我禁用了脚本,果然,CPU 平均下降到 15-30%,但这是我们网站用户体验的重要组成部分。例如,这只是报告(455 个在​​线),并每 15 秒(动态)更新文本。

我的问题是.. 由于 9600 条记录 表上的 SELECT(*) 语句有 15 秒的间隔命中,我该如何优化它以使 SQL 服务器不会崩溃和糟糕用完所有可用内存?

我没有包含脚本,因为它运行良好,查询是问题,但会在需要时提供。

这是我们网站上唯一的 AJAX 脚本。没有进行其他 AJAX 调用。

亲切的问候,

【问题讨论】:

  • 你试过SELECT COUNT(TBLPRIMARYKEY) AS TOTAL FROM USERS WHERE last_access >= DATE_SUB(NOW(), INTERVAL 1 MINUTE) ORDER BY last_access DESC LIMIT 16吗?
  • 我的意思是你只需要用户表中有多少条符合这种条件的记录,不需要包含所有列,只需表主键即可。
  • 主键是 ID,我尝试了 SELECT(id) 并发现差别不大,我认为这也是解决方案,也许在另一种事务情况下。
  • 请发布 A) SHOW CREATE TABLE users 的 TEXT 结果;所以我们可以看到结构和索引 B) EXPLAIN (你的查询);

标签: php jquery mysql ajax performance


【解决方案1】:

我不认为 SQL 查询本身是这里的问题。添加 ORDER BY 和 LIMIT 应该没有任何区别,因为只有一行要排序和限制。您可以考虑为 last_access 列添加索引。

根据您的网站流量,我认为问题在于您设计系统的方式。您是说客户端每 15 秒请求一次您的服务器,这会在最后一分钟向您的数据库询问用户数量。想象一下有 1000 个在线用户,在这种情况下,您每秒将有 66 个查询。

在这种情况下,您应该考虑实现缓存。你用 PHP 标记了你的帖子,Memcached 在 PHP 中很容易实现。将您的 SQL 查询缓存 15 秒,而您的数据库服务器每秒将只有 0.06 个查询。

对于 MyISAM 表,如果 SELECT 从一个表中检索,没有检索到其他列并且没有 WHERE 子句,则 COUNT(*) 被优化为非常快速地返回。 https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count

【讨论】:

  • 这实际上是完美的,我什至没有想到这一点。谢谢!
  • COUNT(*) 在 MyISAM 中被优化只有如果没有WHERE。因此,切换引擎无济于事。
【解决方案2】:
SELECT  COUNT(*) as total
    FROM  users
    WHERE  last_access >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)
    --  ORDER BY  last_access DESC  -- Toss; one output row, nothing to sort
    --  LIMIT  16  -- Toss, only output row

一定要把这个放在桌子上

INDEX(last_access)

COUNT(id) 是,如果有的话,更慢。与COUNT(*) 相同,加上检查id 是否为NOT NULL

有多少个不同的线程?

让我们看看这个查询需要什么——

  1. AJAX 请求到达 Web 服务器。
  2. 它将请求发送到可能已经等待操作的“子”或“线程”。
  3. 如果孩子需要 PHP,则启动该进程。
  4. 连接到 MySQL。
  5. 已执行查询。如果你有索引,这一步很简单。
  6. 事情已关闭。

换句话说,您是否调查过哪个进程占用了大部分 CPU?

【讨论】:

    猜你喜欢
    • 2015-03-23
    • 1970-01-01
    • 2015-06-11
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多