使用DELETE查询MySQL非常慢,查询运行时Apache很奇怪

Bre*_*ser 6 mysql apache apache2

首先,从一些细节来描述整体情况:

  • MySQL(5.1.50)数据库上有一个非常强大的(32个CPU核心,64GB RAM)FreeBSD 8.1-RELEASE机器,它也运行Apache 2.2.
  • Apache每秒平均获得约50次点击.绝大多数这些点击是针对销售平台的API调用.
  • API调用通常需要大约半秒或更短的时间来生成结果,但根据第三方的不同,最多可能需要30秒.
  • 每个API调用都在数据库中存储一行.存储在那里的信息很重要,但只有大约十五分钟,之后它必须到期.
  • 在存储API调用信息的表中(此表的模式如下),InnoDB行级锁定用于在线程之间进行同步(实际上是Apache连接)同时请求相同的信息,这经常发生.这意味着多个线程可能正在等待一行锁定最多30秒,因为API调用可能需要很长时间(但通常不会).
  • 最重要的是,最重要的是要注意一切都在正常情况下完美运行.

也就是说,这是非常高度使用的表(每秒大约500个INSERT,许多SELECT,使用行级锁定)我正在运行DELETE查询:

CREATE TABLE `sales` (
  `sale_id` int(32) unsigned NOT NULL auto_increment,
  `start_time` int(20) unsigned NOT NULL,
  `end_time` int(20) unsigned default NULL,
  `identifier` char(9) NOT NULL,
  `zip_code` char(5) NOT NULL,
  `income` mediumint(6) unsigned NOT NULL,
  PRIMARY KEY  USING BTREE (`sale_id`),
  UNIQUE KEY `SALE_DATA` (`ssn`,`zip_code`,`income`),
  KEY `SALE_START` USING BTREE (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=FIXED
Run Code Online (Sandbox Code Playgroud)

DELETE查询看起来是这样的,并且运行的cron每隔五分钟(我宁愿每分钟运行一次):

DELETE FROM `sales` WHERE 
    `start_time` < UNIX_TIMESTAMP(NOW() - INTERVAL 30 MINUTE);
Run Code Online (Sandbox Code Playgroud)

我已经习惯INT了时间字段,因为很明显MySQL在使用带DATETIME字段的索引时遇到了麻烦.

所以这就是问题:DELETE查询似乎在大多数时间运行良好(可能是10次中的7次).其他时候,查询很快完成,但MySQL似乎在一段时间后被扼杀了.我无法确切地证明它是正在运行的MySQL,但症状发生的时间肯定与运行此查询的时间一致.一切都被呛到了,这是症状:

  • 登录MySQL并使用SHOW FULL PROCESSLIST;,只有少数INSERT INTO销售...查询正在运行,通常有超过一百个.这里的异常实际上是流程列表中缺少任何任务,而不是存在太多任务.似乎MySQL完全停止了连接.
  • 检查Apache服务器状态,Apache已达到MaxClients.所有主题都处于"发送回复"状态.
  • Apache开始使用大量系统时间CPU.负载平均值上升,我已经看到1分钟的平均负载高达100.这台机器的正常负载平均值大约为15.我看到它使用系统CPU(而不是用户CPU),因为我使用GKrellM来监控它.
  • top,有许多Apache进程使用大量的CPU.
  • 网站和API(当然是由Apache提供)在大多数情况下都无法访问.有些请求会通过,但需要大约三到四分钟.其他请求在一段时间之后回复"无法通过/tmp/mysql.sock连接到MySQL服务器"错误 - 这与我在MySQL容量超过并且连接太多时获得的错误相同(只是它没有实际上说连接太多了).
  • MySQL最多接受1024个连接,mysqltuner.pl报告"[!!]最高连接使用率:100%(1025/1024)",这意味着它在一个点上可以处理得更多.通常在正常情况下,最多只有几百个并发MySQL连接.mysqltuner.pl报告没有其他问题,如果有人想要,我很乐意粘贴输出.

最终,大约一两分钟之后,事情就会自行恢复而不需要任何干预.CPU使用率恢复正常,Apache和MySQL恢复正常运行.

那么,我该怎么办?:)我怎么能开始调查为什么会这样?我需要 DELETE查询以各种原因运行,为什么在运行时(但不是所有时间)事情都会变得疯狂?

reg*_*ero 3

很难。这不是回应,而是头脑风暴的开始。

我想说,也许是删除时的重新索引问题,在文档中我们可以找到“快速删除”,然后是“优化表”,以尝试避免多索引合并。

另一种可能是,删除时与至少一个其他线程发生一系列死锁,行锁可能会暂停删除操作,并且删除操作可能会暂停某些下一个行锁。然后你要么检测到死锁,要么检测到未检测到的死锁,从而发生超时。如何检测此类并发中止异常?您重新运行交易吗?如果线程在同一事务中执行许多不同的行锁定,则第一个死锁可能会影响越来越多的线程(交通拥堵)。

您是否尝试在删除事务中锁定表?检查手册,在 Innodb 事务中锁定表的方式或在所有行上获得共享锁。也许你会花一些时间来获取只属于你的表,但如果你的删除速度非常快,没有人会注意到你只花了 1 秒就获取了表。

现在,即使您以前没有尝试过,这也可能是删除正在做的事情。还要检查有关隐式锁的文档,您的删除查询应该使用 start_time 索引,所以我很确定您当前的删除没有锁定所有行(不完全确定,它们锁定所有分析的行,而不仅仅是与 where 匹配的行条件),但删除肯定会阻塞插入。解释了事务执行删除时发生死锁的一些示例。祝你好运!对我来说,现在了解所有锁隔离的影响已经太晚了。

编辑你可以尝试通过更新设置来更改删除删除= 1,并在低使用时间执行真正的删除(如果有的话)。并更改客户端查询以检查此索引已删除状态。