H.3. Restricciones en subconsultas

MySQL 5.0

H.3. Restricciones en subconsultas

Un bug conocido debe ser reparado: Si se compara un valor con una subconsulta usando , , o , y la sentencia regresa un resultado vacio, la comparación tal vez se evalua en un resultado no estandar de en vez de un o .

La sentencia de afuera de la subconsulta puede ser cualquiera de: , , , , , o .

Operaciones de comparacion en registros son soportados solo parcialmente:

  • Para en (), pueden ser -tuplas (especificadas via sintaxis del constructor de registros) y la consulta puede regresar registros de -tuplas.

  • Para {ALL|ANY|SOME} (), debe ser un valor escalar y la subconsulta debe ser una subconsulta de una sola columna; no puede regresar registros con multiples columnas.

En otras palabras, para una subconsulta que regresa registros de -tuplas, esto está soportado:

(, ..., ) IN ()

Pero ésto no es soportado:

(, ..., )  {ALL|ANY|SOME} ()

La razón de soportar comparación entre registros para pero no para otros es que el fue inplementado reescribiendolo como una secuencia de comparaciones y operaciones . Este comportamiento no puede ser usado para , , o .

Constructores de Registros no son bien optimizados. Las siguientes dos expresiones son equivalentes, pero solo la segunda puede ser optimizada:

(col1, col2, ...) = (val1, val2, ...)
col1 = val1 AND col2 = val2 AND ...

La optimización de subconsultas para los no es tan efectiva como para los .

Un caso tipicpo para el pobre desempeño de el es cuando una subconsulta regresa un numero pequeño de registros pero la consulta de afuera regresa un numero grande de registros para ser comparados con el resultado de la consulta.

Las subconsultas en la cláusula no pueden ser subconsultas correlativas. Estás son materializadas (ejecutadas para producir un resultado) antes de evaluar la consulta de afuera, asi que éstas no pueden ser evaluadas por registro de la consulta de afuera.

En general, no puede modificar una tabla y una seleccion de la misma tabla en una subconsulta. Por ejemplo, esta limitación aplica a las sentencias de las siguientes formas:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Excepción: La prohibición precedente no aplica si se usa una subconsulta para la tabla modificada en la cláusula . Ejemplo:

UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);

Aqui la prohibición no aplica debido a que la subconsulta en la cláusula es materializada como una tabla temporal, asi que los registros relevantes en ya han sido seleccionados en el tiempo que la actualización de toma lugar.

El optimizador es más maduro para uniones que para subconsultas, asi que en el mayor de los casos las sentencias que usan subconsultas pueden ser ejecutadas más eficientemente si las reescribe como una union.

Una excepción ocurre para el caso donde una subconsulta puede ser reescrita como una union(join) . Ejemplo:

SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE );

La setencia puede ser reescrita como sigue:

SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND ;

Pero en este caso, la union(join) requiere una operación exxtra y no es más eficiente que la subconsulta.

Futura optimizacion posible: MySQL no reescribe el orden de la union(join) para la evaluacion de subconsulta. En algunos casos, una subconsulta puede ser ejecutada más eficientemente si MySQL la reescribe como una union(join). Este daria a el optimizador mayor posibilidad de elegir entre mas planes de ejecución. Por ejemplo, este puede decidir si leer una tabla o la otra primero.

Ejemplo:

SELECT a FROM outer_table AS ot
WHERE a IN (SELECT a FROM inner_table AS it WHERE ot.b = it.b);

Para esa consulta, MySQL siempre busca primero y después ejecuta la subconsulta en para cada registro. Si tiene muchos registros y tiene pocos registros, la consulta probablemente no será tan rapida como pudiera ser.

La consulta anterior podria ser reescrita asi:

SELECT a FROM outer_table AS ot, inner_table AS it
WHERE ot.a = it.a AND ot.b = it.b;

En éste caso, podemos explorar la tabla pequeña () y buscar registros en , lo cual seria más rapida si existe un indice en .

Futura optimizacion posible: Una subconsulta correlativa es evaluada para cada registro de la consulta de afuera. Una mejor solución es que si el registro de afuerano cambia para el registro anterior, no evaluar la subconsulta otra vez. En vez de esto usar su previo resultado.

Futura optimizacion posible: Una subconsulta en la clausula es evaluada materializando el resultado dentro de una tabla temporal, y esta tabla no usa indices. Esto no permite el uso de indices en comparación con otras tablas en la consulta, aunque pudiera ser útil.

Futura optimizacion posible: Si una subconsulta en la cláusula se asemeja a una vista el algoritmo puede ser aplicado, reescribir la consulta, aplicar el algoritmo resultante y de esa manera los indices pueden ser usados. Las siguientes sentencias contienen una consulta como ésta:

SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;

La stentencia puede ser reescrita con una union(join) como ésta:

SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;

Este tipo de reescritura proveria dos beneficios

  1. Evitar el uso de una tabla temporal la cual nos indices no pueden ser usados. En la consulta reescrita, el optimizador pueden usar los indices en .

  2. Esto da a el optimizador mas opciones a elegir entre diferentes planes de ejecución. Por ejempli, reescribiendo la consulta como un join permite a el optimizador usar o primero.

Futura optimizacion posible: Para los , , , , y con subconsultas no correlativas, usar una tabla hash en memoria para un resultado o una tabla temporal con un idicie para los resultados mas grandes. Ejemplo:

SELECT a FROM big_table AS bt
WHERE non_key_field IN (SELECT non_key_field FROM  WHERE )

En este caso, podriamos crear una tabla temporal:

CREATE TABLE t (key (non_key_field))
(SELECT non_key_field FROM  WHERE )

Entonces, para cada renglon en , hacer un ciclo en basado en .