我有两个表:“电影”和“用户”。 有一个n:那些米之间的关系,说明用户已经看到的电影。这是通过“看到”的表中描述 现在我想找出给定用户,他还没有看到所有的电影。 我的当前的解决方案是这样的:

SELECT *
FROM movies 
WHERE movies.id NOT IN (
     SELECT seen.movie_id 
     FROM seen 
     WHERE seen.user_id=123
)

这工作正常,但似乎并没有很好地进行缩放。有没有更好的办法呢?

有帮助吗?

解决方案

下面是做到这一点的查询,而无需使用子查询方法,你表现出了典型方式。这可满足@ Godeke的请求查看一个联接系溶液。

SELECT * 
FROM movies m
 LEFT OUTER JOIN seen s
 ON (m.id = s.movie_id AND s.user_id = 123)
WHERE s.movie_id IS NULL;

然而,在大多数品牌数据库的这种解决方案可以执行比所述子查询溶液更糟。这是最好使用EXPLAIN分析两个查询,看看哪一个会做的更好给你的架构和数据。

下面是在子查询溶液另一变型:

SELECT * 
FROM movies m
WHERE NOT EXISTS (SELECT * FROM seen s 
                  WHERE s.movie_id = m.id 
                    AND s.user_id=123);

这是一个相关子查询,它必须对外部查询中的每一行进行评估。这通常是昂贵的,和你原来的例子查询是更好的。在另一方面,在MySQL“NOT EXISTS”通常比“column NOT IN (...)

更好

再次必须测试各溶液,并比较结果是肯定的。的这是浪费时间来选择不测量性能的任何解决方案。

其他提示

不仅您的查询工作,这是对这个问题的正确方法是规定。也许你可以找到一个不同的方式来解决这个问题?一个简单的限制对您的选择外应该是非常快的,甚至对于大型表,例如。

看到的是你的连接表,所以是的,这看起来像正确的解决方案。您正在有效地“减去”从电影的全部中看到的电影组ID的集合(一个用户),导致该用户的看不见的电影。

此被称为“负连接”,和可悲NOT IN或NOT EXISTS是最好的选择。 (我很想看到一个负连接语法,这是类似于内/外/左/右连接,但如果ON子句可以是一个减法语句)。

@无子查询比尔的解决方案应该工作,但他指出这是测试您对性能两者兼得的解决方案是一个好主意。我怀疑子查询或没有,整个SEEN.ID指数(当然整个MOVIE.ID指数)将要被评估的两种方式:这将取决于如何优化从那里处理它

如果您的DBMS支持位图索引,你可以尝试一下。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top