复杂的查询使网站极其缓慢

时间:2010-04-10 00:11:53

标签: sql mysql

 select SQL_CALC_FOUND_ROWS DISTINCT media.*, username 
from album as album, album_permission as permission, user as user, media as media , word_tag as word_tag, tag as tag 
where ((media.album_id = album.album_id and album.private = 'yes' and album.album_id = permission.album_id and (permission.email = '' or permission.user_id = '') ) or (media.album_id = album.album_id and album.private = 'no' ) or media.album_id = '0' ) 
and media.status = '1' 
and media.user_id = user.user_id 
and word_tag.media_id = media.media_id 
and word_tag.tag_id = tag.tag_id 
and tag.name in ('justin','bieber','malfunction','katherine','heigl','wardrobe','cinetube') and media.media_type = 'video' 
and media.media_id not in ('YHL6a5z8MV4') 
group by media.media_id 
order by RAND()
#there is limit too, by 20 rows..

我不知道从哪里开始解释这个查询,但请原谅我并问我是否有任何问题。以下是解释。

SQL_CALC_FOUND_ROWS正在计算有多少行并将用于分页,因此它会计算总记录数,即使只显示20个。

DISTINCT将停止显示重复的行。

用户名来自用户表。

专辑,album_permission。它检查专辑是否为私有,如果是,则通过user_id检查用户是否具有权限。

我认为休息很容易理解,但如果您需要了解更多信息,请询问。

我真的很沮丧这个查询和网站很慢或无法打开有时导致此查询。请帮忙

SQL query: EXPLAIN select SQL_CALC_FOUND_ROWS DISTINCT media.*, username from album as album, album_permission as permission, user as user, media as media , word_tag as word_tag, tag as tag where ((media.album_id = album.album_id and album.private = 'yes' and album.album_id = permission.album_id and (permission.email = '' or permission.user_id = '') ) or (media.album_id = album.album_id and album.private = 'no' ) or media.album_id = '0' ) and media.status = '1' and media.user_id = user.user_id and word_tag.media_id = media.media_id and word_tag.tag_id = tag.tag_id and tag.name in ('justin','bieber','malfunction','katherine','heigl','wardrobe','cinetube') and media.media_type = 'video' and media.media_id not in ('YHL6a5z8MV4') group by media.media_id order by RAND() ;
Rows: 6
id  select_type  table  type  possible_keys  key  key_len  ref  rows  Extra
1  SIMPLE  permission  system  album_id  NULL  NULL  NULL  1  Using temporary; Using filesort
1  SIMPLE  album  ALL  PRIMARY  NULL  NULL  NULL  68   
1  SIMPLE  word_tag  ALL  media_id  NULL  NULL  NULL  88383  Using where; Using join buffer
1  SIMPLE  media  eq_ref  media_id,album_id  media_id  34  _site.word_tag.media_id  1  Using where
1  SIMPLE  tag  eq_ref  PRIMARY  PRIMARY  4  _site.word_tag.tag_id  1  Using where
1  SIMPLE  user  eq_ref  PRIMARY  PRIMARY  34  _site.media.user_id  1   

表结构http://pastie.org/912388此链接具有表转储,您可以在phpmyadmin中执行或运行它并查看表的结构。

5 个答案:

答案 0 :(得分:3)

你可以做的最好的事情就是运行查询,但在它前面放一个EXPLAIN,并分析结果。

在不知道该查询中所有表的结构(尤其是索引)的情况下,我们很难给出一个好的答案。

从这开始:Optimizing Queries with EXPLAIN

如果你不能按照那里的建议取得任何进展,那么张贴你的桌子的结构,我们可以从那里帮助你。

答案 1 :(得分:1)

我首先抛弃ORDER BY RAND()。这是一个巨大的性能杀手。请参阅http://www.paperplanes.de/2008/4/24/mysql_nonos_order_by_rand.htmlhttp://jan.kneschke.de/projects/mysql/order-by-rand/

我建议您在选择结果后在代码中进行随机化。

答案 2 :(得分:1)

免责声明:我通常使用SQL Server而非MySQL,这是我第一次尝试实施MySQL Explain计划!特别是我假设它应该从上到下阅读。如果我错了,请有人纠正我!

但是,如果我正确地理解了它,那就是word_tag表说它有88383行。它可以选择一个可能的索引(possible_keys = media_id),但它实际上选择不使用索引(key = null)。

原因似乎是查询中唯一可以限制从word_tag返回的行数的是加入word_tag.media_id = media.media_id and word_tag.tag_id = tag.tag_id,但mediatag都不是直到后来才看你能告诉我这两个表有多少行吗?

编辑:实际上,EXPLAIN中显示了34行和4行。如果您在包含word_tagtag_id列的media_id上添加索引,该怎么办?如果这不会改变计划,可以尝试在这些表http://dev.mysql.com/doc/refman/5.0/en/analyze-table.html

上运行分析表

另外。

  1. 如果删除LIMIT,结果集会返回多少行(即SQL_CALC_FOUND_ROWS的值是多少)?

  2. 如果删除DISTINCT怎么办?那么多少行?

答案 3 :(得分:0)

您是否尝试删除'ORDER BY RAND()',看看是否有所作为?

答案 4 :(得分:0)

正在讨论使用SQL_CALC_FOUND_ROWS

对性能的影响

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

测试您的查询,禁用此选项,看看它是否有所不同(性能)。如果是这样,您可能需要找到一种不同的方法来查找结果集的行数。