2008-12-04 18 views
8

estoy usando esta consulta para obtener todos los empleados de {clientes con el nombre que empieza con "a" minúscula}:MySQL - cómo utilizar índice en donde x IN (<subquery>)

SELECT * FROM employees 
    WHERE client_id IN (SELECT id FROM clients WHERE name LIKE 'a%') 

Columna employees.client_id es una int, con INDEX client_id (index_id). La subconsulta debe en mi humilde opinión devolver una lista de id-s, que luego se utiliza en la cláusula WHERE.

Cuando consulta EXPLAIN, la consulta principal no utiliza índices (type:ALL). Pero cuando yo EXPLAIN una lista tomada de la subconsulta (por ejemplo, SELECT ... WHERE client_id IN (121,184,501)), el EXPLAIN cambia a type:range, y esta consulta se vuelve más rápida en un 50%.

¿Cómo puedo hacer que la consulta utilice el índice para los datos devueltos por subconsulta, o existe una forma más eficiente de recuperar estos datos? (Recuperar la id-list para el servidor de aplicaciones, unirla y enviar una segunda consulta es aún más costoso aquí).

Gracias de antemano.

Respuesta

12
SELECT employees.* 
FROM employees, clients 
WHERE employees.client_id = clients.id 
AND clients.name LIKE 'a%'; 

Debería ser más rápido, ya que el optimizador puede elegir el plan más eficiente. Al escribirlo a su manera con una subconsulta, lo está obligando a seguir los pasos en un cierto orden en lugar de dejar que elija el orden de combinación óptimo.

Como regla general sub-consultas deben ser evitados ya que normalmente serán menos eficiente que una consulta de unión (aunque hay ciertas circunstancias en las que son inevitables)

+0

También podría usar la sintaxis INNER JOIN. – MarkR

+0

He visto casos en los que el optimizador de consultas lo hace realmente incorrecto, y una subconsulta para devolver identificadores se cargó más rápido. Pero fue un caso realmente específico. Ver: http://www.benlumley.co.uk/2008/06/25/mysql-query-optimiser-left-lacking/ si está interesado en detalles. – benlumley

5

¿Ha tratado de hacer esto con un JOIN y no una subseleccion?

SELECT employees.* FROM employees, clients WHERE employees.client_id = clients.id AND clients.name LIKE 'a%'; 
2

Vale la pena señalar que se une a un mejor desempeño que las subconsultas no ser cierto para cada DBMS hay. Sin embargo, sí lo es para MySQL.

0
select * from X as _x where 
    exists(select * from Y as _y where _y.someField = _x.someField) 

debe hacer el truco para usted;)

1
SELECT e.* 
FROM employees e 
WHERE EXISTS ( 
    SELECT 1  
    FROM clients c 
    WHERE c.id = e.client_id 
    AND c.name LIKE 'a%' 
) 

puede volver a escribir la consulta utilizando EXISTE. En MySQL, definitivamente mejora el rendimiento. Para obtener más ayuda optimización, se puede hacer referencia: MySQL-In-Query-Optimization

+0

No creo que el uso de ningún tipo de subconsulta sea una mejora con MySQL. – mat

4

Para una explicación específica sobre por qué

SELECT * FROM employees WHERE client_id IN (SELECT id FROM clients WHERE name LIKE 'a%') 

es más lento que

SELECT * FROM employees WHERE client_id IN (1,2,3,4) 

Salida esta parte del manual de MySQL, particuarly el tercer punto punto: http://dev.mysql.com/doc/refman/5.0/en/subquery-restrictions.html. Además, esto bug report.