简单的MySQL查询需要2到3秒钟才能完成?

3
我有一个相当简单的进程在运行,定期拉取RSS提要并更新MySQL数据库中的文章。
目前,文章表填充了大约130k行。对于找到的每篇文章,处理器都会检查文章是否已经存在。这些查询几乎总是需要300毫秒左右,每10到20次尝试中,它们需要超过2秒钟的时间。
SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;
# Query_time: 2.754567  Lock_time: 0.000000  Rows_sent: 0  Rows_examined: 0

我在guid列上有一个索引,但每当遇到新文章时,它都会被添加到文章表中 - 这会使查询缓存无效(对吗?)。
慢查询日志中的其他一些字段报告了检查了120多行。
当然,在我的开发机器上,这些查询大约需要0.2毫秒。
该服务器是来自Engine Yard Solo(EC2)的虚拟主机,具有1.7GB内存和EC2现在提供的任何CPU。
非常感谢您的任何建议。
更新
事实证明问题出在使用者端。我在'id'上有一个索引,但却查询'guid'。
在'guid'上添加索引将每个查询时间降至0.2毫秒。
感谢所有人给出的有用提示!

1.7MB 的内存相当小了。我的 286 电脑只有 1MB 的内存。 - pjp
是的,请编辑和修复那个金额,因为我看到后觉得“不可能”。 - Jeff Ferland
修正了内存注释 - 应该是GB。谢谢! - Luke Bayes
4个回答

5

运行:

EXPLAIN SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;

注意前面的EXPLAIN。这将告诉您MySQL正在做什么。除非您的计算机严重超载和/或抛锚,否则很难相信从索引中探测一行可能需要2.7秒。考虑到0的行数,我猜MySQL进行了全表扫描以找到没有任何东西,这可能意味着您没有认为自己有的索引。
回答您的另一个问题,每当对articles表进行任何更改时,涉及该表的所有查询缓存条目都将无效。

1

日志显示没有读取或检查任何行,因此问题不在于您的查询,而很可能是您的服务器。EC2的致命弱点是其IO/s,也许MySQL需要从磁盘加载索引,但服务器的磁盘完全饱和。

如果您的索引足够小以适应内存(确保my.cnf分配足够的内存给key_buffer(MyISAM)或innodb_buffer_pool_size(InnoDB)),则可以使用以下方法预加载它:

SELECT guid FROM articles

检查 EXPLAIN ,确保它显示“使用索引”。如果没有,那么应该这样:

SELECT guid FROM articles FORCE INDEX (guid) WHERE LENGTH(guid) > 0

或者,如果guid不是您的PRIMARY KEY或UNIQUE,您可以删除其索引并创建另一个索引列,以便在索引大小的一小部分中快速检索记录。 列guid_crc32将是一个INT UNSIGNED,并将保存guid的CRC32。

ALTER TABLE articles ADD COLUMN guid_crc32 INT UNSIGNED, ADD INDEX guid_crc32 (guid_crc32);
UPDATE articles SET guid_crc32 = CRC32(guid);

你的SELECT查询将会是这样的:

SELECT id FROM articles WHERE guid = 'http://example.com/feed.rss' AND guid_crc32 = CRC32('http://example.com/feed.rss') LIMIT 1;

优化器应该使用在guid_crc32上的索引,这比通过guid搜索更快且更小。


我刚刚注意到Luke说同一个查询被反复执行会在几十次尝试后变得很慢,这削弱了我从磁盘加载索引的理论。除非服务器为索引保留的内存非常少,以至于每隔几十次尝试就必须将其交换出去。 - Josh Davis

0

假设GUID已经建立索引,而ID是您的主键,那么可能出现了一些“问题”。在这种情况下,这是一个仅索引查询。索引被从内存中移除,磁盘很忙,可能会出现问题。

根据您的更新/插入/删除模式,您的数据库可能需要执行“优化”命令。

我想看到的SQL命令输出:

show table status like 'articles';
explain SELECT id FROM `articles` WHERE (guid = 'http://example.com/feed.rss')  LIMIT 1;
explain articles;

我想查看的系统命令(假设为Linux)的输出:

iostat 5 5

请告诉我们您有多少内存,因为1.7MB是错误的,或者可能正在发生一些非常令人兴奋的事情。

编辑 my.cnf 中可用于您的SQL服务器的内存容量?


0
如果这个表被频繁更新,那么MySQL可能无法正确更新索引计数。尝试使用"CHECK TABLE articles"来更新索引计数并查看您的表是否正常。
另外,请尝试在开发和生产环境中对查询进行EXPLAIN,如果结果不同,请尝试使用OPTIMIZE TABLE。
这些是MyISAM还是InnoDB表?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接