3

我们最近遇到了一个我以前从未见过的问题,大约 3 个小时,我们的一个 Mysql 表变得非常慢。该表包含论坛帖子,目前大约有 100 万行。变慢的查询在我们的应用程序中很常见:

SELECT * FROM `posts` WHERE (`posts`.forum_id = 1)  ORDER BY posts.created_at DESC LIMIT 1;

我们在 (forum_id, created_at) 上的帖子表上有一个索引,通常允许此查询和排序在内存中进行。但是,在这三个小时内,并不多。在此期间,通常瞬时查询的范围从 2 秒到 45 秒不等。然后又恢复正常了。

我仔细研究了我们的慢查询日志,没有其他任何异常。我查看了 New Relic(这是一个 Rails 应用程序),所有其他操作的运行速度基本上与正常速度相同。我们今天没有异常数量的消息帖子。我在我们的日志中找不到其他奇怪的东西。并且数据库没有交换,当它仍然有可用的内存可用时。

我想知道 Mysql 是否可以来回改变对给定查询使用哪些索引的想法,并且出于某种原因,它今天开始决定对这个查询进行几个小时的全表扫描?但如果这是真的,为什么它会停止进行全表扫描呢?

有没有其他人遇到过无视原因的间歇性缓慢查询?或者你对如何调试这样的问题有什么创造性的想法吗?

4

2 回答 2

2

我会尝试MySQLEXPLAIN语句...

EXPLAIN SELECT * FROM `posts` WHERE (`posts`.forum_id = 1)  ORDER BY posts.created_at DESC LIMIT 1;

在 Rails 代码中检查 MySQL 响应时间可能是值得的,如果它超过阈值,则运行EXPLAIN并在某处记录详细信息。

表锁定也浮现在脑海中 - 当 SELECT 正在进行时,posts 表是否由 cronjob 或大量查询更新?

希望那有所帮助!

于 2009-08-10T10:16:51.577 回答
2

在我工作的一个站点上,我们最近从 MyISAM 切换到 InnoDB,我们发现一些具有 WHERE 和 ORDER BY 子句的简单选择查询正在使用 ORDER BY 子句的索引,从而导致表扫描以找到少数几个所需的行(但是,见鬼,当它最终找到它们时不需要对它们进行排序!)

如链接文章中所述,如果您的 LIMIT 值较小,则您的 ORDER BY 子句是主键的第一个成员(因此文件上的数据按其排序),并且有很多结果与您的 WHERE 子句匹配,使用 ORDER BY 索引对 MySQL 来说不是一个坏主意。但是,我认为 created_at 不是您的主键的第一个成员,因此在这种情况下这不是一个特别聪明的想法。

如果您没有更改任何内容,我不知道为什么 MySQL 会切换索引,但我建议您尝试在相关表上运行 ANALYZE TABLE。如果结果集足够小,您还可以更改查询以删除 LIMIT 和 ORDER BY 子句并在应用程序级别进行排序;或者你可以添加一个 USE INDEX 提示,这样它就永远不会猜错。

您还可以将 wait_timeout 值更改为更小的值,以便这些使用错误索引的查询永远不会完成(但也不会滞后所有合法查询)。即使 wait_timeout 很小,您仍然可以交互式地运行长查询,因为有一个单独的配置参数。

于 2009-08-10T10:23:59.253 回答