我运行一个接受用户请求并将其添加到名为“queue”的表中的服务,该表有3个字段:useridqueuenumberprocessed
我存储了需要处理的任务(我可以处理的任务比收到的请求少)
不幸的是,我对mysql优化知之甚少,我的处理脚本(我并行运行50个版本)使用的查询如下:

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

当代码的任何实例需要处理一行时,它会将其标记为processed=1,这样其他实例就不会占用它。
因此,当我运行50个这段代码的实例时,MySQL数据库的负担会加重(而且我只有4GB的ram)
因此,我得到的数据如下:
Traffic:

Received 15.8 MiB
Sent    42.9 GiB

ø per hour

Received: 3 MiB
Sent: 8.1 GiB

来自phpmyadmin的一些统计信息:
如何优化?能够并行运行此代码,但不列出整个表?
//编辑:
创建表的结果是:
创建表queue(
useridint(11)不为空,
queuenumberint(11)非空自动递增,
processedtinyint(1)不为空,
主键(queuenumber),
唯一键queuenumberqueuenumber),
唯一键
)引擎=InnoDB AUTO_INCREMENT=121617默认字符集=latin1

最佳答案

使用RDBMS实现队列是一种反模式:http://blog.engineyard.com/2011/5-subtle-ways-youre-using-mysql-as-a-queue-and-why-itll-bite-you
然而,如果你坚持有办法做到始终如一没有种族条件。
首先,在新行排队时实现一个通知(在MySQL之外),这样您就不必在快速循环中轮询新数据了——也许这就是您的流量如此之高的原因。我已经看到UDP多播用于此或UNIX信号。
现在check table正在使用InnoDB

SHOW CREATE TABLE `queue`;

如果你需要把它改成InnoDB
ALTER TABLE `queue` ENGINE=InnoDB;

如果有多个使用者处理作业,请确保锁定没有竞争;每次使用者遇到新作业时,它首先应尝试使用唯一的process-id更新该作业。每个使用者应在表上执行更新,以按id将行/作业分配给使用者
您需要在表上有一个process列
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或线程id。您可以通过检查查询响应中受影响的行(最快)或尝试获取行详细信息来判断更新是否找到了行-可能您将返回0行,这意味着更新没有执行任何操作-其他使用者获得了作业。
SELECT * FROM `queue` WHERE process = ? AND processed = 0;

当消费者完成行/作业时,可以将该行上的processed设置为0(也许您应该考虑表上的auto inc主键,这样您就可以准确地寻址一行)
ALTER TABLE `queue` ADD `id` bigint unsigned NOT NULL auto_increment FIRST, ADD primary key (`id`);

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

关于php - 优化mysql数据库-任务列表耗尽了我的服务器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20478186/

10-13 03:22