Mysql Update性能突然变得糟透了

时间:2011-04-22 13:02:05

标签: mysql ubuntu-10.10

MySQL 5.1,Ubuntu 10.10 64位,Linode虚拟机。

所有表格都是 InnoDB

我们的一台生产机器使用包含31个相关表的MySQL数据库。在一个表格中,有一个字段包含的显示值可能每天更改几次,具体取决于条件。

在使用时间内,这些对显示值的更改会在一天中懒散地应用。脚本定期运行并检查可能导致更改的一些廉价条件,并在满足条件时更新显示值。但是,这种惰性方法无法捕获应更新显示值的所有可能情况,以便在工作时间内将后台进程负载降至最低。

每晚一次,脚本会清除表中存储的所有显示值并重新计算所有值,从而捕获所有可能的更改。这是一个更昂贵的操作。

这一直持续了大约6个月。突然,3天前,夜间剧本的运行时间从平均40秒变为11分钟。

存储数据的总体比例没有显着变化。

我尽力调查,突然运行较慢的脚本部分是写入新显示值的最后一个更新语句。给定行的(INT(11))id和新的显示值(也是INT),每行执行一次。

update `table` set `display_value` = ? where `id` = ?

有趣的是,所有先前值的清除执行如下:

update `table` set `display_value` = null

此声明仍然以与以往相同的速度运行。

display_value字段未编入索引。 id是主键。 table中有4个其他外键在执行期间的任何时候都没有被修改。

最后的曲线球:如果我将此架构转储到测试VM,并执行相同的脚本,它将在40秒内运行而不是11分钟。我没有尝试在生产机器上重建架构,因为这不是一个长期的解决方案,我想了解这里发生了什么。

我的索引有什么问题吗?在对同一行进行了数千次更新之后,他们是否会陷入其中?


更新

我能够通过在架构上运行optimize来完全解决此问题。由于InnoDB不支持优化,因此强制重建,并解决了问题。也许我的索引已损坏了?

mysqlcheck -A -o -u <user> -p

1 个答案:

答案 0 :(得分:2)

UPDATE语句有可能不使用id上的索引,但是,对于像您这样的查询来说,这是非常不可能的(如果可能的话)。

您的表是否有可能被长时间运行的并发查询/ DML锁定?该表使用哪个引擎?

此外,逐个记录更新表效率不高。您可以批量方式将值加载到临时表中,并使用单个命令更新主表:

CREATE TEMPORARY TABLE tmp_display_values (id INT NOT NULL PRIMARY KEY, new_display_value INT);

INSERT
INTO    tmp_display_values
VALUES
(?, ?),
(?, ?),
…;

UPDATE  `table` dv
JOIN    tmp_display_values t
ON      dv.id = t.id
SET     dv.new_display_value = t.new_display_value;