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
答案 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;