Pregunta

Tengo dos tablas: 'películas' y de los usuarios. Hay un n: relación entre los m, describiendo lo que las películas que un usuario ha visto. Esto se describe con una mesa de 'visto' Ahora quiero saber de un usuario determinado, todas las películas que no ha visto. Mi solución actual es la siguiente:

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

Esto funciona bien, pero no parece que escalar muy bien. ¿Hay un mejor enfoque a esto?

¿Fue útil?

Solución

Esta es una forma típica de hacer esta consulta sin utilizar el método subconsulta que apareciste. Esto puede satisfacer la petición del Godeke @ para ver una solución a base de unir.

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;

Sin embargo, en la mayoría de las marcas de la base de datos esta solución puede realizar peor que la solución subconsulta. Lo mejor es usar EXPLAIN para analizar tanto las consultas, para ver cuál se hará mejor dada su esquema y los datos.

Esta es otra variante de la solución de subconsulta:

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

Esta es una consulta correlacionada, que debe ser evaluado para cada fila de la consulta externa. Por lo general, esto es caro, y su ejemplo de consulta original es mejor. Por otro lado, en MySQL "NOT EXISTS" es a menudo mejor que "column NOT IN (...)"

Una vez más, debe probar cada solución y comparar los resultados para estar seguro. Es una pérdida de tiempo de elegir la solución sin medir el rendimiento.

Otros consejos

No sólo hace su trabajo de consulta, que es el enfoque correcto para el problema como se indica. Tal vez se puede encontrar una forma diferente de abordar el problema? Un LÍMITE sencilla en su exterior seleccione debe ser muy rápido, incluso para tablas grandes, por ejemplo.

visto es su tabla de unión, de modo que sí, esto se parece a la solución correcta. Usted está efectivamente "restando" el conjunto de ID de cine en VE (para un usuario) de la totalidad en las películas, lo que resulta en las películas no vistas para ese usuario.

Esto se llama un "negativo se unen", y lamentablemente NO EN existe o no son las mejores opciones. (Me encanta ver a un negativo sintaxis de combinación que era similar al interior / exterior / IZQUIERDA / DERECHA se une, pero donde la cláusula ON podría ser una declaración de sustracción).

@ solución de factura sin una subconsulta debe trabajar, aunque, como se señaló, es una buena idea probar su solución para el rendimiento en ambos sentidos. Sospecho que subconsulta o no, todo el índice SEEN.ID (y por supuesto todo el índice MOVIE.ID) va a ser evaluado en ambos sentidos: eso dependerá de cómo el optimizador lo maneja desde allí

.

Si su DBMS soporta índices de mapa de bits, puede probar con ellos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top