如何优化这个非常慢的 MySQL 查询?
Posted
技术标签:
【中文标题】如何优化这个非常慢的 MySQL 查询?【英文标题】:How can I optimize this VERY slow MySQL query? 【发布时间】:2014-07-04 04:29:06 【问题描述】:我有一个基于 WordPress 的网站,它为区域科学期刊编目学术文章。
简单地说,系统有几千个“帖子”,每个都有一个“pub_type”分类法,其中只选择了一个术语:“手稿”,或其他。
每个帖子还有与其相关的各种其他分类法/术语。
目标:获取特定分类法的术语列表。对于每个术语,计算与其相关的帖子数,并确定其中有多少帖子在“pub_type”分类中设置了“手稿”。
当前查询:
SELECT term_id, term_id as term_id_b, name, slug,
( SELECT COUNT(id) FROM wp_posts WHERE id IN
( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN
( SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE term_id = term_id_b )
) AND post_status = "publish" ) as count,
( SELECT COUNT(id) FROM wp_posts WHERE id IN
( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN
( SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE term_id IN
( SELECT term_id FROM wp_terms WHERE term_id = term_id_b )
)
)
AND id IN
( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN
( SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE term_id =
( SELECT term_id FROM wp_terms WHERE name = "Manuscript" )
AND taxonomy = "pub_type" )
)
AND post_status = "publish"
) as manuscript_count
FROM wp_terms
WHERE term_id IN
( SELECT term_id FROM wp_term_taxonomy WHERE taxonomy = "'.$taxonomy.'" )
ORDER BY name ASC
虽然此查询确实有效,但它的运行速度非常慢...根据服务器负载在 3-5 分钟之间。太糟糕了,为了保持网站性能,我不得不将查询结果缓存到 JSON 文本文件中,并且只让查询每 2 小时运行一次。
我知道这里的主要问题是我对所有内容都使用了子查询。虽然我正在尝试了解有关使用联接的更多信息,但我还不够了解以任何其他方式编写此查询。
谁能就我如何驯服这只野兽提供一些见解或建议?
编辑:这是查询的 EXPLAIN 输出的屏幕截图:
http://i.imgur.com/Axaqun3.png
【问题讨论】:
很多时候子查询,WHERE EXISTS
比WHERE IN
快。但是,为了给您一个更好的答案,我需要查看查询计划。您能否将EXPLAIN PLAN
输出添加到您的问题中?
如果我想去那里,我不会从这里开始。 :-( 考虑提供适当的 DDL(和/或 sqlfiddle)以及所需的结果集。
你是说你想这样做:计算每个词条为 pub_type 分类法的帖子数?
【参考方案1】:
请参阅this great post 了解IN
的使用以及它如何对查询速度产生负面影响。上面写满了你的问题。
本质上,使用传统的IN(values)
查询,您只需搜索每个值。在子查询 IN
中,就像你一样 (IN(SELECT)
)。
其中,作者引用了 mysql 的手册:
如果内部和外部查询分别返回 M 和 N 行,则执行时间将变为 O(MxN) 的顺序,而不是 O(M+N),因为对于不相关的子查询。
使用此逻辑,您将wp_posts
作为外部查询,并在其中嵌套wp_terms_relationship
10 行,并在 that 内再次嵌套wp_terms
。那个是949*(10*1))
。第二次你只有两层嵌套,但因为最后一层只有一行,所以仍然是同样的影响:你最终解析了 9490 行。
子查询不是你的朋友。虽然有时它们可能是必要的,但它们几乎总是可以使用JOIN
来解决。根据您的目标,这似乎没有太大不同。通过重写此查询并扩展以尝试使用 JOIN...ON
,您会发现经过短暂的学习曲线后,阅读您自己的代码会更容易更遵循其逻辑进展,并且很可能,看到它也加快了。至少,尽可能使用join
s。以后你会感谢自己的。
【讨论】:
以上是关于如何优化这个非常慢的 MySQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章