2011-04-07 89 views
1

环境:Rails的2.3.11,MySQL 5.1中(InnoDB的)简单的MySQL查询服用时间太长

我的Rails应用程序已经遇到零星用简单的查询服用时间太长,完成和瓶颈整个应用程序的能力问题被更新。这些查询通常与论坛相关,即网站的最高流量部分,以及具有(目前为止)最多更新的论坛。下面是从MySQL慢日志拉到一个示例查询的例子:

# Query_time: 46.900202 Lock_time: 0.000030 Rows_sent: 0 Rows_examined: 0 
SET timestamp=1302172666; 
UPDATE `forum_topics` 
SET `views` = 153, `updated_at` = '2011-04-07 10:36:59' 
WHERE `id` = 1213305; 

这是一个非常简单查询,应该是非常快的,但是在这种情况下,花了将近47秒的时间完成。该服务器上的平均负载不会超过2,所以这不是问题。其他一些相关的要点是:

  • 无论views也不updated_at是 索引。
  • 尽管自动增加值可能是 是1.2M,但实际上在此表中只有 70K记录。
  • 慢速查询日志中超过90%的查询与此类似。

我在这里找的是关于接下来要解决此问题的步骤的一些建议。

谢谢。

P.S.方案/索引如下:

CREATE TABLE `forum_topics` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `forum_category_id` int(11) DEFAULT NULL, 
    `title` varchar(255) NOT NULL, 
    `sticky` tinyint(1) DEFAULT '0', 
    `views` int(11) DEFAULT '0', 
    `created_at` datetime DEFAULT NULL, 
    `updated_at` datetime DEFAULT NULL, 
    `last_post_created_at` datetime DEFAULT NULL, 
    `slug` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `index_forum_topics_on_created_at` (`created_at`), 
    KEY `index_forum_topics_on_forum_category_id` (`forum_category_id`), 
    KEY `index_forum_topics_on_sticky` (`sticky`) 
) ENGINE=InnoDB AUTO_INCREMENT=1215414 DEFAULT CHARSET=utf8; 
+0

:)'WHERE '身份证'= 1213305;'你的数据库看起来相当巨大的。什么指标? – fl00r 2011-04-07 19:28:26

+0

'id'索引? – 2011-04-07 19:28:30

+0

你的表模式和索引是什么? – IanNorton 2011-04-07 19:28:39

回答

0

尝试将LIMIT添加到您的查询。认为这应该是这样的:

... WHERE `id` = 1213305 
    LIMIT 1 
1

1)也许有一个硬件错误 - 磁盘重置。 2)id密钥索引? 3)通信问题。 4)是时间戳一个局部变量?它是否应该在它之前没有'@'?

+0

1.这是可能的,但如果是这样,似乎我会在其他地方看到问题。 2.是3. 通过这个,你指的是数据库服务器和应用服务器之间的通信问题?在我看到这个问题发生的时候,情况并非如此。 4.时间戳本地变量由Rails(ActiveRecord)在内部编写/使用 - 我敢肯定这里没有关系。 – modulaaron 2011-04-08 15:44:57

0

where子句通常是长时间运行查询的罪魁祸首。我可以看到,在这个查询中,只有'id'列被引用。我会检查它是否被索引。如果是,我会检查它是否正确索引。如果索引已经存在,我甚至会尝试重新索引'id'列

0

在表上运行优化可能会有所帮助,尤其是在磁盘上仍存在大量已删除行的情况下。

除此之外,什么上查询说明揭示它是如何运行的(当然,该查询的选择版本)

+0

我在桌子上运行了'ANALYZE TABLE'并且状态返回了OK。此外,运行'mysqlcheck --analyze --all-databases'显示所有表都可以。 'EXPLAIN'没有任何异常。 – modulaaron 2011-04-08 16:41:34

+0

但是,运行mysqltuner。pl确实显示'[!!]总碎片表:78'。同样,运行'SHOW TABLE STATUS WHERE Data_free> 0'将返回所有表格(它不适用于我的其他类似网站,虽然它们是v5.0,而不是v5.1)。在其中一个表上运行'OPTIMIZE'不会将此Data_free值更改为0,因此mysqltuner.pl会继续将表显示为碎片。 – modulaaron 2011-04-08 16:42:22

+0

你已经运行了优化,以前在这里生活的评论是毫无意义的。我的歉意 – preinheimer 2011-04-08 17:03:29

0

有这里没有真正足够的信息来告诉你到底为什么你的查询缓慢进行,但:

如果这是一个MYISAM表,这些更新可能需要很长时间,因为MYISAM在表上缺少行级锁定。这会影响您的查询性能,因为您需要运行的每个SELECT在表上获得READ LOCK(不允许进一步写入)。此外,MYISAM表上的UPDATE需要另一个锁,它会阻止所有其他UPDATES/INSERTS/SELECTS运行。因此,如果您有10个这样的查询正在运行,它们不会同时运行,并且必须等待彼此完成。

我不认为指数是你的问题就在这里,因为你提到的自动递增,并使用ID字段作为更新,所以我敢肯定这是你的主键。

+0

所以,显然,这不是MYISAM vs INNODB - 我在回答后添加了您的模式。哈哈。 – 2011-04-07 19:39:03

+0

从头开始,他实际上拥有'MySQL 5.1(InnoDB)',但如果表是MyISAM,我也不确定。 – 2011-04-07 20:25:23

1

有许多数据库产品有很多原因突然摊位 - 和MySQL并不孤单。以下是一些示例:

  • 您需要从存储(在forum_topics上没有可用表缓存条目)加载表描述。此操作是序列化的 - 您可以排在另一个表上的另一个用户的后面。

  • 您正在使用查询缓存和查询缓存(可能)支离破碎。 (?也许你已经auto_extend_increment设置为高)

  • 的InnoDB正在执行类似延伸的数据文件的大小,这会导致短暂的暂停活动

这些只是一个例子 - 有肯定是更多的原因。你需要做的是使用分析工具,如poor man's profiler。它会给你一个堆栈跟踪,以确切地查询被阻止的位置。搜索堆栈跟踪的bugs.mysql.com,或尝试询问诸如Percona forums之类的内容。

0

这是一个小老头,但我只是偶然发现了它,也许it's对他人有所帮助,...

有了这样的问题,你可以使用内部探查:

mysql> SET PROFILING=1; 
mysql> [your query] 
mysql> SHOW PROFILE FOR QUERY 1; 

如果你的问题是随机发生的,另一个进程可能锁定了表。您可以使用SHOW FULL PROCESSLISTSHOW OPEN TABLES来查看此。

此外,与大表,你可以运行到了缓冲区的内存问题 - 有很多关于这个好页。 http://dev.mysql.com/doc/refman/5.1/en/innodb-tuning.htmlhttp://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/是一个伟大的开始