优化PHP页面:MySQL瓶颈

rg8*_*g88 2 php mysql optimization

我有一个页面需要37秒加载.在加载时,它会通过屋顶固定MySQL的CPU使用率.我没有写这个页面的代码,而且相当复杂,所以瓶颈的原因对我来说并不是很明显.

我对它进行了分析(使用kcachegrind)并发现页面上的大部分时间用于执行MySQL查询(90%的时间用于25个不同的mysql_query调用).

查询采用以下形式,其中tag_id在25个不同的调用中都发生了变化:

SELECT * FROM tbl_news WHERE news_id
 IN (select news_id from
 tbl_tag_relations WHERE tag_id = 20)

每个查询大约需要0.8秒才能完成,并且会有一些较长的延迟时间进行测量...因此完全加载页面需要37秒.

我的问题是,是否使用导致问题的嵌套选择格式化查询的方式?或者它可能是其他一百万个中的任何一个?关于如何应对这种缓慢的任何建议都值得赞赏.

在查询上运行EXPLAIN给了我这个(但是我不清楚这些结果的影响......主键上的NULL看起来很糟糕,是吗?返回的结果数量对我来说似乎很高最后只返回少量结果):

1    PRIMARY     tbl_news   ALL NULL    NULL    NULL    NULL    1318    Using where
2   DEPENDENT SUBQUERY  tbl_tag_relations   ref FK_tbl_tag_tags_1   FK_tbl_tag_tags_1   4   const   179 Using where

cle*_*tus 5

我在AppDevelopers所做的数据库开发错误中解决了这一问题.基本上,支持加入聚合.IN不是这样的聚合,但同样的原则适用.一个好的优化将使这两个查询的性能相当:

SELECT * FROM tbl_news WHERE news_id
 IN (select news_id from
 tbl_tag_relations WHERE tag_id = 20)
Run Code Online (Sandbox Code Playgroud)

SELECT tn.*
FROM tbl_news tn
JOIN tbl_tag_relations ttr ON ttr.news_id = tn.news_id
WHERE ttr.tag_id = 20
Run Code Online (Sandbox Code Playgroud)

因为我相信Oracle和SQL Server都可以,但MySQL却没有.第二个版本基本上是即时的.有数十万行我在我的机器上进行了测试,并通过添加适当的索引获得了第一个版本的亚秒级性能.带索引的连接版本基本上是即时的,但即使没有索引也能正常运行.

顺便说一句,我使用的上述语法是你应该喜欢做的连接.它比将它们放在WHERE子句中更清楚(正如其他人所建议的那样),并且上面的内容可以用ANSI SQL方式做某些事情,而左外连接是WHERE条件不能的.

所以我会在下面添加索引:

  • tbl_news(news_id)
  • tbl_tag_relations(news_id)
  • tbl_tag_relations(tag_id)

并且查询将几乎立即执行.

最后,不要使用*来选择所需的所有列.明确命名它们.稍后添加列时,您会遇到麻烦.