mysql - 这个查询有什么问题? EXPLAIN 对我来说很好

标签 mysql optimization performance

我正在浏览一个应用程序并尝试优化一些查询,但我真的很难处理其中的一些查询。这是一个例子:

SELECT `Item` . * , `Source` . * , `Keyword` . * , `Author` . *
FROM `items` AS `Item`
JOIN `sources` AS `Source` ON ( `Item`.`source_id` = `Source`.`id` )
JOIN `authors` AS `Author` ON ( `Item`.`author_id` = `Author`.`id` )
JOIN `items_keywords` AS `ItemsKeyword` ON ( `Item`.`id` = `ItemsKeyword`.`item_id` )
JOIN `keywords` AS `Keyword` ON ( `Keyword`.`id` = `ItemsKeyword`.`keyword_id` )
JOIN `keywords_profiles` AS `KeywordsProfile` ON ( `Keyword`.`id` = `KeywordsProfile`.`keyword_id` )
JOIN `profiles` AS `Profile` ON ( `Profile`.`id` = `KeywordsProfile`.`profile_id` )
WHERE `KeywordsProfile`.`profile_id` IN ( 17 )
GROUP BY `Item`.`id`
ORDER BY `Item`.`timestamp` DESC , `Item`.`id` DESC
LIMIT 0 , 20;

这个需要 10-30 秒...在引用的表中,大约有 50 万个作者行,以及大约 75 万个项目和 items_keywords 行。其他所有内容都少于 500 行。

这是解释输出: http://img.skitch.com/20090220-fb52wd7jf58x41ikfxaws96xjn.jpg

EXPLAIN 对我来说相对较新,但我逐行检查了这一点,一切似乎都很好。不确定我还能做什么,因为我对所有内容都有索引...我错过了什么?

它所在的服务器只是 slicehost 上的一个 256 分片,但上面没有其他任何东西在运行,并且 CPU 在它运行之前是 0%。然而它仍然在处理这个查询。有什么想法吗?

编辑:一些进一步的信息;真正令人沮丧的事情之一是,如果我重复运行此查询,它只需要不到 0.1 秒。我假设这是由于查询缓存,但如果我在它之前运行 RESET QUERY CACHE,它仍然运行得非常快。只有在我稍等片刻或运行其他一些查询后,10-30 秒才会返回。所有表都是 MyISAM...这是否表明 MySQL 正在将内容加载到内存中,这就是为什么它运行得如此之快的原因?

编辑 2:非常感谢大家的帮助……更新……我把所有内容都缩减为:

SELECT i.id
FROM items AS i
ORDER BY i.timestamp DESC, i.id DESC
LIMIT 0, 20;

尽管数据库中只有 750k 条记录,但始终需要 5-6 秒。一旦我将第 2 列放在 ORDER BY 子句上,它几乎是即时的。显然这里发生了几件事,但是当我将查询缩减为:

SELECT i.id
FROM items AS i
JOIN items_keywords AS ik ON ( i.id = ik.item_id )
JOIN keywords AS k ON ( k.id = ik.keyword_id )
JOIN keywords_profiles AS kp ON ( k.id = kp.keyword_id )
WHERE kp.profile_id IN (139)
ORDER BY i.timestamp DESC
LIMIT 20;

仍然需要 10 多秒...我还能做什么?

次要的好奇心:在解释中,items_keywords 的行列始终为 1544,无论我在查询中使用什么 profile_id。它不应该根据与该个人资料关联的项目数量而改变吗?

编辑 3:好吧,这太荒谬了 :)。如果我完全删除 ORDER BY 子句,事情会非常迅速,并且临时表/文件排序从解释中消失。目前在 item.timestamp 列上有一个索引,但它是否由于某种原因没有被使用?我以为我记得一些关于 mysql 只使用每个表的索引之类的东西?我应该在该查询引用的项目表上的所有列(source_id、author_id、timestamp 等)上创建一个多列索引吗?

最佳答案

试试这个,看看效果如何:

SELECT i.*, s.*, k.*, a.*
FROM items AS i
 JOIN sources AS s ON (i.source_id = s.id)
 JOIN authors AS a ON (i.author_id = a.id)
 JOIN items_keywords AS ik ON (i.id = ik.item_id)
 JOIN keywords AS k ON (k.id = ik.keyword_id)
WHERE k.id IN (SELECT kp.keyword_id
           FROM keywords_profiles AS kp
           WHERE kp.profile_id IN (17))
ORDER BY i.timestamp DESC, i.id DESC
LIMIT 0, 20;

我将几个连接提取到一个不相关的子查询中,因此您不必执行 GROUP BY 将结果映射到不同的行。

实际上,在我的示例中,您可能仍会为每个 i.id 获取多行,具体取决于有多少关键字映射到给定项目以及 profile_id 17。

您的 EXPLAIN 报告中报告的 filesort 可能是由于 GROUP BYORDER BY 使用不同字段的组合。

我同意@ʞɔıu 的回答,加速可能是因为 key 缓存。

关于mysql - 这个查询有什么问题? EXPLAIN 对我来说很好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/567991/

相关文章:

c# - 如何优化这个表达式? LINQ?

php - MySQL通过计算结果获取数据

MySQL - 如果除 ID 之外所有记录都相等,则更新

MYSQL 复杂查询select语句

java - Spring Data Repository 多线程性能

c# - 关于字符串实习表现的问题

java - ArrayList快速查找自定义对象

mysql - mysql 触发问题

c++ - cvSetImageROI 似乎不够快

SQL查询优化合并表