我有一个基于 WordPress 的网站,用于为区域科学期刊编目学术文章。
简单地说,系统有几千个“帖子”,每个帖子都有一个“pub_type”分类法,其中只选择了 1 个术语:“手稿”或其他。
每个帖子还有与之相关的各种其他分类法/术语。
目标:获取特定分类法的术语列表。对于每个术语,计算与其相关的帖子数量,并确定这些帖子中有多少在“pub_type”分类法中设置了“Manuscript”。
当前查询:
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 输出的屏幕截图:
最佳答案
参见 this great post关于 IN
的使用以及它如何对查询速度产生负面影响。这上面写满了您的问题。
本质上,使用传统的 IN(values)
查询,您只需搜索每个值。在子查询 IN
中,您有 (IN(SELECT)
)。
其中,作者引用了MySQL的手册:
If the inner and outer queries return M and N rows, respectively, the execution time becomes on the order of O(MxN), rather than O(M+N) as it would be for an uncorrelated subquery.
使用此逻辑,您将 wp_posts
作为外部查询,并在其中嵌套了 10 行的 wp_terms_relationship
,并在 that 中嵌套了, wp_terms
再次。那个是 949*(10*1))
。第二次你只有两层嵌套,但因为最后一层只有一行,它仍然是相同的影响:你最终解析了 9490 行。
子查询不是你的 friend 。虽然有时它们可能是必要的,但它们几乎总是可以使用 JOIN
来解决。根据您的目标,这似乎没有太大不同。通过重写此查询并尝试使用 JOIN...ON
,您会发现经过短暂的学习曲线后, 阅读您自己的代码会容易得多,遵循其逻辑进程,并且很可能会看到它也在加速。至少,尽可能使用 join
。稍后您会感谢自己。
关于mysql - 如何优化这个非常慢的 MySQL 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23683086/