如何使用重复的子查询优化此查询?

时间:2013-10-01 07:33:21

标签: database sqlite postgresql

我有这个查询正确回答了这个问题: 平均评分最高的电影名称是什么?

select title 
from (
   select movies.title, avg(rating) avgrating 
   from movies, rentals 
   where movies.movieid = rentals.movieid 
   group by movies.title
) a 
where avgrating = (select max(avgrating) 
                   from (select movies.title, avg(rating) avgrating 
                   from movies, rentals 
                   where movies.movieid=rentals.movieid 
                   group by movies.title) b) 
order by title desc

唯一的问题是在我的大型数据库上运行需要几分钟。我无法想到如何加快速度。基本上子查询a和b是等价的,但据我所知,我必须重复它,因为where子句不能看到' a'子查询。 重要提示:最高平均评分可以达到平局,并且查询必须返回与平局中一样多的标题。 我还要提一下,加入是必要的,因为标题在电影表中并且评级在租赁表中。

Movies (
    movieId INTEGER PRIMARY KEY,
    title TEXT,
    year INTEGER
)

Rentals (
    cardNo INTEGER,
    movieId INTEGER,
    date DATE,
    rating INTEGER,
    PRIMARY KEY(cardNo, movieID, date),
    FOREIGN KEY (cardNo) REFERENCES Customers,
    FOREIGN KEY (movieId) REFERENCES Movies
)

1 个答案:

答案 0 :(得分:1)

您只能使用公用表表达式运行子查询一次:

with avg_ratings as (
   select movies.title, 
          avg(rentals.rating) as avgrating 
   from movies
     join rentals on movies.movieid = rentals.movieid 
   group by movies.title
)    
select title 
from avg_ratings 
where avgrating = (select max(avgrating) from avg_ratings);

这也可以使用窗口函数编写:

with avg_ratings as (
   select movies.title, 
          avg(rentals.rating) as avgrating 
   from movies
     join rentals on movies.movieid = rentals.movieid 
   group by movies.title
)    
select title
from (
   select title, 
          avgrating,
          dense_rank() over (order by avgrating desc) as rating_rank
   from avg_ratings
) t
where rating_rank = 1;

不确定哪个版本更快。


如果您仍然遇到性能问题,则需要发布表的定义,索引和执行计划(有关如何发布与性能相关的问题的详细信息,请参阅此处:http://wiki.postgresql.org/wiki/SlowQueryQuestions