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