评级系统查询

时间:2010-07-14 02:36:20

标签: mysql sql database-design optimization denormalization

我已经为MySQL中的电影建立了一个评级系统,但关注的是当我的查询总结所有评级并对其进行划分时,它可能需要总结数百万条记录。

我想到的一个解决方案是基本上在memcached中缓存评级,并且只对未经常使用的项目进行评级操作。然而,即便如此,对于没有被评级很多的电影,如果有人确实去检查评级,如果必须计算很多行,查询可能需要很长时间。

我想到的另一个解决方案是构建一个不断更新表的临时表,但是如果电影被评级很多并且有人试图访问它,我相信INNODB会进行行锁定,所以这会导致从长远来看是僵局还是什么?

1 个答案:

答案 0 :(得分:4)

由于评级相当静态且数据集很大,因此您可以在用户评价电影时缓存(非规范化)电影记录中的数据。您需要跟踪两个投票的数量和投票的总和,因此平均值是准确的。您的电影评级是在您需要时动态计算的。这是架构:

create table movie as (
movie_id int not null primary key,
-- your current columns
vote_count int,
vote_sum int
);

然后使用视图来帮助

create view movie_view as
select
  *,
  vote_sum/vote_count as vote_average
from movie;

假设您有一个如下所示的表:

create table user_movie_vote (
user_id int references user,
movie_id int references movie,
vote int
);

您可以使用触发器为您保持最新的投票总数:

delimiter ~
create trigger movie_vote_trg after insert on user_movie_vote
for each row
begin
  update movie set
  vote_count = vote_count + 1,
  vote_sum = vote_sum + new.vote
  where movie_id = new.movie_id;
end~
delimiter ;

如果可以更新投票,则需要:

delimiter ~
create trigger movie_vote_trg after update on user_movie_vote
for each row
begin
  update movie set
  vote_sum = vote_sum + new.vote - old.vote
  where movie_id = new.movie_id;
end~
delimiter ;

如果可以删除投票,则需要:

delimiter ~
create trigger movie_vote_trg after delete on user_movie_vote
for each row
begin
  update movie set
  vote_sum = vote_sum - old.vote,
  vote_count = vote_count - 1
  where movie_id = new.movie_id;
end~
delimiter ;