我们最近遇到过一个我以前从未见过的问题,大约3个小时,我们的一个Mysql表变得非常慢。此表包含论坛帖子,目前大约有一百万行。变慢的查询在我们的应用程序中非常常见:
SELECT * FROM `posts` WHERE (`posts`.forum_id = 1) ORDER BY posts.created_at DESC LIMIT 1;
我们在(forum_id,created_at)上的posts表上有一个索引,它通常允许在内存中进行此查询和排序。但是,在这三个小时内,并非如此。什么是通常的即时查询,范围从这段时间内的2秒-45秒。然后它恢复正常。
我通过慢速查询日志进行了仔细研究,没有其他任何看起来与众不同。我查看了New Relic(这是一个Rails应用程序),所有其他操作的运行速度与正常情况基本相同。我们今天没有异常数量的留言。我在日志中找不到任何其他奇怪的东西。当数据库仍然可以使用时,数据库没有交换。
我想知道Mysql是否可以来回改变用于给定查询的索引,无论出于何种原因,它开始决定今天在这个查询上进行全表扫描几个小时?但如果这是真的,为什么它会停止进行全表扫描?
有没有其他人遇到过一个间歇性的慢查询而无法理由?或者你对如何调试这样的问题有什么创意吗?
答案 0 :(得分:2)
我会尝试MySQL EXPLAIN
声明......
EXPLAIN SELECT * FROM `posts` WHERE (`posts`.forum_id = 1) ORDER BY posts.created_at DESC LIMIT 1;
可能值得检查Rails代码中的MySQL响应时间,如果超过阈值,则运行EXPLAIN
并在某处记录详细信息。
Table locking也让人想起 - 当SELECT正在进行时,是否通过cronjob或大量查询更新了posts表?
希望有所帮助!
答案 1 :(得分:2)
在我工作的网站上,我们最近从MyISAM切换到InnoDB,并we found that some simple select queries which had both WHERE and ORDER BY clauses were using the index for the ORDER BY clause,导致进行表扫描以找到所需的几行(但是,哎呀,他们不需要在排序时进行排序它终于找到了所有!)
如链接文章中所述,如果您有一个小的LIMIT值,您的ORDER BY子句是主键的第一个成员(因此文件中的数据按其排序),并且有许多结果与您的匹配WHERE子句,使用ORDER BY索引对MySQL来说并不是一个坏主意。但是,我认为created_at不是主键的第一个成员,所以在这种情况下它不是一个特别聪明的想法。
我不知道为什么MySQL如果你没有改变任何东西就会切换索引,但我建议你尝试在相关的表上运行ANALYZE TABLE。如果结果集足够小,您也可以更改查询以删除LIMIT和ORDER BY子句并在应用程序级别进行排序;或者你可以添加a USE INDEX hint所以它永远不会猜错。
您还可以change the wait_timeout value to something smaller,以便使用错误索引的这些查询永远不会完成(但也不会滞后所有合法查询)。即使使用较小的wait_timeout,您仍然可以交互式地运行长查询,因为有一个单独的配置参数。