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
我在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条件不能的.
所以我会在下面添加索引:
并且查询将几乎立即执行.
最后,不要使用*来选择所需的所有列.明确命名它们.稍后添加列时,您会遇到麻烦.