2011-06-23 24 views
5

Soy un noobie de consulta MySQL, así que estoy seguro de que esta es una pregunta con una respuesta obvia.MySQL Group By y HAVING

Pero, estaba viendo estas dos consultas. ¿Regresarán diferentes conjuntos de resultados? Entiendo que el proceso de clasificación comenzaría de manera diferente, pero creo que devolverán los mismos resultados y la primera consulta será un poco más eficiente.

de consulta 1: HAVING, entonces Y

SELECT user_id 
FROM forum_posts 
GROUP BY user_id 
    HAVING COUNT(id) >= 100 
    AND user_id NOT IN (SELECT user_id FROM banned_users) 

Consulta 2: WHERE, luego tener

SELECT user_id 
FROM forum_posts 
WHERE user_id NOT IN(SELECT user_id FROM banned_users) 
GROUP BY user_id 
    HAVING COUNT(id) >= 100 

Respuesta

1

En realidad, la primera consulta será menos eficiente (HAVING aplica después WHERE).
ACTUALIZACIÓN

Algunos pseudo código para ilustrar cómo sus consultas se ejecutan ([muy] versión simplificada).
Primera consulta:
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3. Grupo, cuenta, etc.
4. Excluir los registros desde el primer conjunto de resultados si se presentan en la segunda

segunda consulta
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3. Excluir los registros desde el primer conjunto de resultados si se presentan en la segunda
4. Agrupar, contar, etc.

El orden de los pasos 1,2 no es importante, mysql puede elegir lo que crea que es mejor. La diferencia importante está en los pasos 3,4. Tener se aplica después de GROUP BY. Agrupar suele ser más costoso que unirse (en este caso, se pueden considerar los registros como una operación de unión), por lo que cuantos menos registros tenga para agrupar, mejor será el rendimiento.

+0

genial, gracias! Interesante, tendré que hacer algunas pruebas. Pensé que era más eficiente porque hay menos registros para comparar la porción NOT IN banned_users después de agruparla que antes. Si eso tiene sentido. – kimmothy

+0

Sí, esa condición se probaría solo para agruparla por resultados, no todos, antes de la agrupación. – aorcsik

+0

@kimmothy: La subconsulta en 'NOT IN' realmente necesita ejecutarse solo una vez. – a1ex07

0

Las condiciones HAVING se aplican al agrupadas por resultados, y ya que agrupa por user_id, todos sus valores posibles estarán presentes en el resultado agrupado, por lo que la colocación de la condición user_id no es importante.

+0

La colocación es importante. Si se aplica el 'WHERE ', la agrupación se realiza en menos filas (incluso cero), por lo que el COUNT() debe calcularse solo para esas filas. Si se deja para la cláusula 'HAVING', la agrupación (y el recuento) se realiza en todas las filas y luego se verifica la condición. Resultado: si los usuarios prohibidos representan un gran porcentaje de todos los usuarios, la diferencia es que la velocidad será excelente (proporcionalmente) –

+0

Por supuesto, la diferencia de velocidad solo existe si el optimizador cede con diferentes planes para las 2 consultas. –

+0

Gracias por señalar, realmente aprendí mucho de las respuestas aquí. :) – aorcsik

-1

No, no da los mismos resultados.

Debido primera consulta se filtrar registros de recuento (id) condición

Otros registros del filtro de consulta y luego aplicar tener cláusula.

segunda consulta se escribe correctamente

+2

Como dice que los resultados serán diferentes, difícilmente podrá decir cuál está escrito correctamente antes de saber qué problema se está resolviendo.Por lo menos, ambos son correctos * sintácticamente *. Y, de hecho, los resultados serán los mismos también. Es la eficiencia en la que diferirán. –

+0

@Andriy: ¿está seguro de que hay una diferencia en la eficiencia? –

+0

@ypercube: esperaría tener que evaluar después de DÓNDE, y, de hecho, incluso después de GROUP BY (que, creo, se calcula después de DONDE también). Por lo tanto, la primera consulta calcularía innecesariamente los recuentos de las filas que luego se descartarían en función de 'user_id'. El segundo filtra en 'user_id' antes de agregar. –

0

Para mí, segunda consulta es más eficiente, ya que reduce el número de registros para GROUP BY y HAVING.

Alternativamente, puede intentar la siguiente consulta para evitar el uso de IN:

SELECT `fp`.`user_id` 
FROM `forum_posts` `fp` 
LEFT JOIN `banned_users` `bu` ON `fp`.`user_id` = `bu`.`user_id` 
WHERE `bu`.`user_id` IS NULL 
GROUP BY `fp`.`user_id` 
HAVING COUNT(`fp`.`id`) >= 100 

Espero que esto ayude.

0

Ya tiene respuestas que las dos consultas mostrarán los mismos resultados y varias opiniones para las cuales una es más eficiente.

Mi opininion es que habrá una diferencia en la eficiencia (velocidad), sólo si los rendimientos Optimizer con planes diferentes para las 2 consultas. Creo que para las últimas versiones de MySQL los optimizadores son lo suficientemente inteligentes como para encontrar el mismo plan para cualquiera de las consultas, por lo que habrá sin diferencias en absoluto, pero por supuesto se pueden probar y ver los planes de ejecución con EXPLAIN o ejecutando las 2 consultas contra algunas tablas de prueba.

Yo usaría la segunda versión en cualquier caso, solo para jugar seguro.


quiero añadir que:

  • COUNT(*) es generalmente más eficiente que COUNT(notNullableField) en MySQL. Hasta que esto se solucione en futuras versiones de MySQL, use COUNT(*) donde corresponda.

Por lo tanto, también se puede utilizar:

SELECT user_id 
FROM forum_posts 
WHERE user_id NOT IN 
    (SELECT user_id FROM banned_users) 
GROUP BY user_id 
HAVING COUNT(*) >= 100 
  • También hay otras maneras de lograr la misma (a NOT IN) sub-resultados antes de aplicar GROUP BY.

Usando LEFT JOIN/NULL:

SELECT fp.user_id 
FROM forum_posts AS fp 
    LEFT JOIN banned_users AS bu 
    ON bu.user_id = fp.user_id 
WHERE bu.user_id IS NULL 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100 

usando NOT EXISTS:

SELECT fp.user_id 
FROM forum_posts AS fp 
WHERE NOT EXISTS 
    (SELECT * 
    FROM banned_users AS bu 
    WHERE bu.user_id = fp.user_id 
) 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100 

¿Cuál de los 3 métodos es más rápido depende de sus tamaños de mesa y una gran cantidad de otros factores, así que lo mejor es poner a prueba con tus datos