2009-11-19 15 views
6

que tienen consulta como esta:¿Puedo forzar a mysql a realizar una subconsulta primero?

SELECT `table_1`.* from `table_1` 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE `table_1`.`id` IN(
    SELECT `id` FROM [...] 
) 
AND [more conditions] 

Cuando uso EXPLICAR, hay 'subconsulta dependiente' al final, pero quiero que este sub consulta que se realizó por primera vez, antes de que otras condiciones.

¿Es posible?

Respuesta

2

Primero puede seleccionar el resultado de la subconsulta en una tabla temporal y luego unirse a ella en la consulta principal.

2

La mejor manera es poner las condiciones WHERE para table1 en una subconsulta en la cláusula FROM. Ejem:

SELECT `table_1`.* 
FROM (
     SELECT * FROM `table_1` WHERE `table_1`.`id` IN (...) 
    ) 
    INNER JOIN `table_2` [...] 
    INNER JOIN `table_3` [...] 
WHERE [more conditions] 
-1

Por desgracia, no, no se puede. Las sub consultas se ejecutan realmente una vez para cada fila en la consulta externa.

De hecho, le sugiero que convierta esto a otra unión, usando table_1.id como su clave para la otra tabla.

13
SELECT `table_1`.* 
FROM `table_1` 
INNER JOIN 
     `table_2` [...] 
INNER JOIN 
     `table_3` [...] 
WHERE `table_1`.`id` IN 
     (
     SELECT `id` 
     FROM [...] 
     ) 
     AND [more conditions] 

Si la tabla interna está correctamente indexada, la subconsulta aquí no se está "ejecutando" en absoluto en un sentido estricto de la palabra.

Dado que la subconsulta es una parte de una expresión IN, la condición se inserta en la subconsulta y se transforma en EXISTS.

De hecho, esta subconsulta se evalúa en cada paso:

EXISTS 
(
SELECT NULL 
FROM [...] 
WHERE id = table1.id 
) 

en realidad se puede ver que en la descripción detallada proporcionada por EXPLAIN EXTENDED.

Es por eso que se llama DEPENDENT SUBQUERY: el resultado de cada evaluación depende del valor de table1.id. La subconsulta como tal no está correlacionada, es la versión optimizada la que está correlacionada.

MySQL siempre evalúa la cláusula EXISTS después de los filtros más simples (ya que son mucho más fáciles de evaluar y existe la probabilidad de que la subconsulta no se evalúe en absoluto).

Si desea que la subconsulta para ser evaluado todos a la vez, vuelve a escribir la consulta como esta:

SELECT table_1.* 
FROM (
     SELECT DISTINCT id 
     FROM [...] 
     ) q 
JOIN table_1 
ON  table_1.id = q.id 
JOIN table_2 
ON  [...] 
JOIN table_3 
ON  [...] 
WHERE [more conditions] 

Esto obliga a la subconsulta para ser líder en la unión, que es más eficiente si la subconsulta es pequeña comparada a table_1, y menos eficiente si la subconsulta es grande en comparación con table_1.

Si hay un índice en [...].id utilizado en la subconsulta, la subconsulta se realizará utilizando un INDEX FOR GROUP-BY.

+0

Problema al presionar la subconsulta hacia abajo es que esto no es posible si la subconsulta depende de una parte constante de la consulta externa (consulte https://stackoverflow.com/questions/44859809/how-to-optimize-dependent-subquery -with-constant-expression) – andig

3

esto es un error conocido en mysql: http://bugs.mysql.com/bug.php?id=25926

una solución útil es para empujar hacia abajo la subconsulta en otro select * from (subquery) as dt tipo subconsulta.

+0

El error que menciona afecta solo a las subconsultas 'GROUP BY/DISTINCT'. Un predicado 'IN' sobre una subconsulta con una cláusula' DISTINCT' es equivalente a 'JOIN'. – Quassnoi

+1

no, el problema también ocurre en las consultas que no incluyen 'GROUP BY 'o' DISTINCT'. Desaprobar esto es simple: empujar la subconsulta hacia otro nivel como sugiero y ver si la SUBCAPA DEPENDIENTE cambia a una tabla DERIVADA. (y ¿cómo sabe usted que esta consulta no tiene GROUP BY? el póster original no proporcionó la consulta real.) – longneck

+0

Esa solución funcionó para mí: tomó una consulta que parecía de 32 minutos a 0.452 segundos. ¡Gracias! – Deebster

Cuestiones relacionadas