MySQL - 如何有效地获取ID最低的行?

Tom*_*Tom 5 mysql message-queue database-performance

是否有更快的方法来更新匹配特定条件的MySQL表的最旧行,而不是使用ORDER BY id LIMIT 1以下查询中的情况?

UPDATE mytable SET field1 = '1' WHERE field1 = 0 ORDER BY id LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

注意:

  • 假设主键是,id并且还有一个索引field1.
  • 我们正在更新一行.
  • 我们没有严格更新最旧的行,我们正在更新与条件匹配的最旧行.
  • 我们想要更新最旧的匹配行,即最低的id,即FIFO队列的头部.

问题:

  • ORDER BY id必要吗?MySQL如何默认订购?

现实世界的例子

我们有一个DB表用于电子邮件队列.当我们要将电子邮件排队以发送给我们的用户时,会添加行.行由cron作业删除,每分钟运行一次,在该分钟内尽可能多地处理并每行发送1封电子邮件.

我们计划放弃这种方法,并使用GearmanResque之类的东西来处理我们的电子邮件队列.但与此同时,我有一个问题,我们如何有效地标记队列中最旧的项目进行处理,即具有最低ID的行.此查询完成工作:

mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 ORDER BY id LIMIT 1");
Run Code Online (Sandbox Code Playgroud)

但是,由于扩展问题,它出现在mysql慢日志中很多.当表有500,000行时,查询可能需要10秒以上.问题是这个表自首次引入以来已经大量增长,现在有时有50万行,开销为133.9 MiB.例如,我们每天INSERT 6000个新行可能180次,并且删除大致相同的数字.

为了阻止查询出现在慢速日志中,我们删除了ORDER BY id以阻止整个表格的大规模.即

mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 LIMIT 1");
Run Code Online (Sandbox Code Playgroud)

...但是新查询不再总是获得id最低的行(尽管通常会这样).除了使用之外,是否有更有效的方法来获取id最低的行ORDER BY id

作为参考,这是电子邮件队列表的结构:

CREATE TABLE IF NOT EXISTS `email_queue` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `time_queued` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when item was queued',
  `mem_id` int(10) NOT NULL,
  `email` varchar(150) NOT NULL,
  `processingID` int(2) NOT NULL COMMENT 'Indicate if row is being processed',
  PRIMARY KEY (`id`),
  KEY `processingID` (`processingID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)

Jon*_*ack 1

听起来您有其他进程锁定表,阻止您的更新及时完成 - 您是否考虑过使用 innodb ?