Mysql非常慢的子查询优化

时间:2014-12-29 21:30:49

标签: mysql sql database performance subquery

我正在使用大量数据构建S​​QL查询,但查询速度太慢

我有3张桌子; moviesmovie_categoriesskipped_movies
movies表已标准化,我正在尝试根据类别查询电影,同时从skipped_movies表中排除ID。

但是我在我的查询中尝试使用WHERE IN和WHERE NOT IN。

movies表约有。 200万行(id,name,score)
movie_categories约。 500万(id,movie_id,category_id)
skipped_movies约有。 1k行(id,movie_id,user_id)

skipped_movies表非常小10到20行时,查询速度非常快。 (大约40 - 50毫秒)但是当表格大约有1k的数据时,我在查询上大约需要7到8秒。

这是我正在使用的查询。

  

SELECT SQL_NO_CACHE * FROM`movies` WHERE`id`IN(SELECT`movors_id` FROM`movie_categories` WHERE`category_id` = 1)AND`id` NOT IN(SELECT`movie_id` FROM`lepeped_movies` WHERE`user_id` = 1)AND`得分'< = 9 ORDER BY`得分`DESC LIMIT 1;

我已经尝试了许多想到的方法,但这是最快的方法。我甚至尝试了EXISTS方法。

我正在使用SQL_NO_CACHE进行测试。

我猜ORDER BY语句运行速度非常慢。

3 个答案:

答案 0 :(得分:1)

假设(movie_id,category_id)在movies_categories表中是唯一的,我将使用连接操作而不是子查询来获取指定的结果。

要排除“跳过”电影,反连接模式就足够了......这是一个左外连接,用于在skipped_movies中查找匹配的行,然后在WHERE子句中使用谓词排除找到的任何匹配,只留下行没有比赛。

SELECT SQL_NO_CACHE m.*
  FROM movies m
  JOIN movie_categories c 
    ON c.movie_id = m.id 
   AND c.category_id = 1
  LEFT
  JOIN skipped_movies s
    ON s.movie_id = m.id
   AND s.user_id = 1
 WHERE s.movie_id IS NULL
   AND m.score <= 9
 ORDER
    BY m.score DESC
 LIMIT 1

适当的指数可能会提高绩效......

... ON movie_categories (category_id, movie_id)
... ON skipped_movies (user_id, movie_id)

答案 1 :(得分:1)

大多数IN / NOT IN查询可以使用JOIN / LEFT JOIN表示,这通常可以提供最佳性能。

将您的查询转换为使用联接:

SELECT m.*
FROM movies m
JOIN movie_categories mc ON m.id = mc.movie_id AND mc.category_id = 1
LEFT JOIN skipped_movies sm ON m.id = sm.movie_id AND sm.user_id = 1
WHERE sm.movie_id IS NULL
AND score <= 9
ORDER BY score DESC
LIMIT 1

答案 2 :(得分:0)

您的查询似乎没问题。只是一个小小的调整需要。您可以将* with替换为表中的列/属性名称。它将使这个查询比以往任何时候都更快。由于*操作非常慢