我运行一项服务,该服务接受用户请求并将其添加到名为“queue”的表中,该表具有 3 个字段:userid
、queuenumber
和 processed
.
我将需要处理的任务存储在那里(我可以处理的任务少于我收到的请求)
不幸的是,我对 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 的一些统计数据:
我该如何优化它?为了能够并行运行此代码但不列出整个表?
//编辑:
建表结果为:
创建表 队列
(
userid
int(11) NOT NULL,
queuenumber
int(11) NOT NULL AUTO_INCREMENT,
已处理
tinyint(1) NOT NULL,
主键(queuenumber
),
唯一键 queuenumber
(queuenumber
),
唯一键 userid
(userid
)
) ENGINE=InnoDB AUTO_INCREMENT=121617 DEFAULT CHARSET=latin1
最佳答案
使用 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(也许您应该考虑在表上使用 auto-inc 主键,您可以准确地处理单行)
ALTER TABLE `queue` ADD `id` bigint unsigned NOT NULL auto_increment FIRST, ADD primary key (`id`);
如果您的消费者因任何原因崩溃,您可以通过查看行来判断发生了什么 - 如果 processed = 0 但已设置进程,则在处理该行时出现崩溃。
关于php - 优化 mysql 数据库 - 任务列表耗尽了我的服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20478186/