【问题标题】:Optimizing mysql database - List of tasks eats up my server优化 mysql 数据库 - 任务列表占用了我的服务器
【发布时间】:2013-12-09 18:44:58
【问题描述】:

我运行一个接受用户请求并将其添加到一个名为“队列”的表中的服务,该表有 3 个字段:useridqueuenumberprocessed

我在那里存储需要处理的任务(我可以处理的任务比我收到的请求少)

不幸的是,我对 mysql 优化并不太了解,我的处理脚本(我并行运行 50 个版本)使用如下查询:

SELECT * FROM `queue` WHERE `processed` = 0 ORDER BY `queue`.`queuenumber`

当代码的任何实例占用一行来处理时,它会将其标记为processed = 1,这样它就不会被其他实例占用。

因此,当我运行 50 个此代码实例时,MySQL 数据库会变得很重(而我只有 4GB 的内存)

因此,我得到了如下统计数据:

Traffic:

Received 15.8 MiB
Sent    42.9 GiB    

ø per hour

Received: 3 MiB
Sent: 8.1 GiB

来自 phpmyadmin 的一些统计数据:

如何优化它?为了能够并行运行此代码但不列出整个表?

// 编辑:

创建表的结果是:

创建表queue ( userid int(11) 非空, queuenumber int(11) NOT NULL AUTO_INCREMENT, processed tinyint(1) 非空, 主键 (queuenumber), 唯一键queuenumber (queuenumber), 唯一键 userid (userid) ) ENGINE=InnoDB AUTO_INCREMENT=121617 默认字符集=latin1

【问题讨论】:

  • 请发布您的完整CREATE TABLE 声明,包括所有密钥。另外,您多久访问一次数据库?您提供的内存使用率数据并没有那么高。
  • 怎么这么慢?桌子变大了吗?你有queue.queuenumber 的索引吗?
  • 第 1 步。除非您确实需要每个字段,否则不要选择 *。
  • 您是否使用任何缓存?你的存储引擎是什么?
  • 如何获得 CREATE_TABLE 语句?我需要导出表格吗?

标签: php mysql sql optimization


【解决方案1】:

使用 RDBMS 实现队列是一种反模式:http://blog.engineyard.com/2011/5-subtle-ways-youre-using-mysql-as-a-queue-and-why-itll-bite-you

但是,如果您坚持有办法在没有竞争条件的情况下始终如一地做到这一点。

首先在新行入队时实现通知(在 MySQL 之外),这样您就不必在快速循环中轮询新数据 - 也许这就是您的流量如此之高的原因。我已经看到用于此的 UDP 多播或 UNIX 信号。

现在检查表正在使用 InnoDB

SHOW CREATE TABLE `queue`;

如果需要改成 InnoDB

ALTER TABLE `queue` ENGINE=InnoDB;

如果您有多个消费者处理作业,请确保您的锁定是无竞争的;每次消费者遇到新工作时,它应该尝试做的第一件事是使用其唯一的进程 ID 对其进行更新。每个消费者都应该对表执行更新,以通过 ID 将行/作业分配给消费者

您的桌子上需要有一个流程列

ALTER TABLE `queue` ADD `process` int unsigned default NULL;

添加索引以帮助您有效地选择行

ALTER TABLE `queue` ADD KEY (`processed`,`process`);

现在您的消费者可以在他们的代码中运行以下代码

UPDATE `queue` SET process = ? WHERE process IS NULL AND processed = 0 LIMIT 1;

你可以设置吗?成为消费者的 pid 或 thread-id。您可以通过检查查询响应中受影响的行(最快)或尝试获取行详细信息来判断更新是否找到了一行 - 也许您将返回 0 行,这意味着更新什么也没做 - 不同的消费者得到了工作。

SELECT * FROM `queue` WHERE process = ? AND processed = 0;

当您的消费者完成行/作业时,它可以在该行上将处理设置为 0(也许您应该考虑表上的自动增量主键,您可以准确地处理单行)

ALTER TABLE `queue` ADD `id` bigint unsigned NOT NULL auto_increment FIRST, ADD primary key (`id`);

如果您的消费者因任何原因崩溃,您可以通过查看该行来判断发生了什么 - 如果已处理 = 0 但已设置进程,则在处理该行时发生了崩溃。

【讨论】:

  • 更新发生在选择“每次消费者遇到新工作时,它应该尝试做的第一件事是使用它的唯一进程 ID 更新它”
  • 错过了,很好的答案。
猜你喜欢
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 1970-01-01
  • 2012-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多