我的Sql查询非常慢(60秒),任何人都有改进的想法?

时间:2011-05-19 22:23:54

标签: mysql join performance

我的查询很慢。我在3张桌子之间搜索。 Se_movies = 80000条记录,se_movie_contenttags = 1.6 mil记录,se_movie_descriptiontags -200000条记录

两个简化查询。

或 - 慢速

SELECT SQL_NO_CACHE  count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT  JOIN 
( 
  SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
  LEFT  JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
  ON dtag.did=ctag.cid
UNION 
  SELECT did , cid , ifnull(cid,did) as uid  FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
  RIGHT  JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
  ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE  ( se_movies.movie_title LIKE '%dog%') **OR**  (  (cid IS NOT NULL or  did IS NOT NULL) and uid IS NOT NULL )

AND - 快速

SELECT SQL_NO_CACHE  count(movie_id)
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id
LEFT  JOIN 
( 
  SELECT did , cid , ifnull(cid,did) as uid FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
  LEFT  JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
  ON dtag.did=ctag.cid
UNION 
  SELECT did , cid , ifnull(cid,did) as uid  FROM ( SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog') ) AS dtag
  RIGHT  JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog') ) AS ctag
  ON dtag.did=ctag.cid
)
AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE   ( se_movies.movie_title LIKE '%dog%') **AND**  (  (cid IS NOT NULL or  did IS NOT NULL) and uid IS NOT NULL )

每个人

( se_movies.movie_title LIKE '%dog%') - around 300
 (cid IS NOT NULL or  did IS NOT NULL) and uid IS NOT NULL - return 595

但如果他们中的任何人返回50或更少,那就很快。

基本上,如果任何关键字在每个标签和电影表标题中都超过500,则需要60秒

否则为2.3秒

有更好的方法吗?

我知道你们可以在这两者之间做UNION ...... 和其他东西......和

搜索 - 标题OR(contenttag或desctag)

问题是查询的变化太多......

如果数据在两个不同的表中,它是否有问题?无论如何加速他们?。

感谢。

系统 - mysql apache2 php5 ubuntu - amazon aws。

解释 enter link description here

通过

解决

SELECT SQL_NO_CACHE count(movie_id) FROM se_movies LEFT JOIN se_users ON se_movies.movi​​e_user_id = se_users.user_id 内部联接 (SELECT tag_object_id AS movieid FROM se_movie_contenttags WHERE tag_name IN('dog') 联盟 SELECT tag_object_id AS movieid FROM se_movie_descriptiontags WHERE tag_name IN('dog') 联盟 SELECT s1.movi​​e_id AS movieid FROM se_movies as s1 WHERE s1.movi​​e_title LIKE'%dog%' 联盟 SELECT s2.movi​​e_id AS movieid FROM se_movies as s2 WHERE s2.movi​​e_desc LIKE'%dog%' ) AS tagobjects ON se_movies.movi​​e_id = tagobjects.movi​​eid

.5sec

1 个答案:

答案 0 :(得分:0)

如果se_movie_descriptiontagsse_movie_contenttags包含(movie_id, tag)对并且您想要包含所有包含特定代码的电影,我会将tagobjects内嵌视图替换为:

SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags`
WHERE `tag_name` IN ('dog')
UNION
SELECT `tag_object_id` FROM `se_movie_contenttags`
WHERE `tag_name` IN ('dog')

此查询将返回在se_movie_descriptiontagsse_movie_contenttags表中的任何一个或两个中都带有“dog”标签的电影ID。然后你可以在主查询中删除OR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL)

最终的完整查询将是:

SELECT SQL_NO_CACHE count(movie_id)
FROM
    se_movies LEFT JOIN
    se_users ON se_movies.movie_user_id=se_users.user_id INNER JOIN 
    ( 
        SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags`
        WHERE `tag_name` IN ('dog')
        UNION
        SELECT `tag_object_id` FROM `se_movie_contenttags`
        WHERE `tag_name` IN ('dog')
    ) AS tagobjects ON se_movies.movie_id=tagobjects.uid
WHERE (se_movies.movie_title LIKE '%dog%')

另外,请注意(se_movies.movie_title LIKE '%dog%')单独是性能杀手,因为无法使用movie_title列上的索引对其进行优化,并且肯定会导致表扫描。这主要是因为条件以通配符开头。对于这种情况,我建议研究MySQL的全文搜索功能。