1

MySQL 5.1,Ubuntu 10.10 64bit,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是主键。还有 4 个其他外键在table执行期间的任何时候都不会被修改。

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

我的索引有问题吗?在对同一行进行数千次更新后,它们会变得笨拙吗?


更新

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

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

1 回答 1

2

There is a chance the the UPDATE statement won't use an index on id, however, it's very improbable (if possible at all) for a query like yours.

Is there a chance your table are locked by a long-running concurrent query / DML? Which engine does the table use?

Also, updating the table record-by-record is not efficient. You can load your values into a temporary table in a bulk manner and update the main table with a single command:

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;
于 2011-04-22T13:14:43.897 回答