2008-10-23 19 views
21

Tengo la siguiente consulta:¿En qué orden se evalúa MySQL JOINs?

SELECT c.* 
FROM companies AS c 
JOIN users AS u USING(companyid) 
JOIN jobs AS j USING(userid) 
JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123; 

Tengo las siguientes preguntas:

  1. es la sintaxis USO EN sinónimo de sintaxis?
  2. ¿Estas uniones se evalúan de izquierda a derecha? En otras palabras, ¿esta consulta dice: x = empresas ÚNASE a usuarios; y = x UNIR trabajos; z = y ÚNETE userac contadores;
  3. Si la respuesta a la pregunta 2 es sí, ¿es seguro asumir que la tabla de empresas tiene columnas companyid, userid y jobid?
  4. No entiendo cómo la cláusula WHERE se puede utilizar para recoger las filas de la tabla empresas cuando se está refiriendo al alias "j"

se agradecería cualquier ayuda!

Respuesta

23
  1. USING (fieldname) es una forma abreviada de decir ON table1.fieldname = table2.fieldname.

  2. SQL no define el 'orden' en el que se realizan las INSCRIPCIONES porque no es la naturaleza del idioma. Obviamente, se debe especificar un orden en la declaración, pero una UNIÓN INTERNA puede considerarse conmutativa: puede enumerarlos en cualquier orden y obtendrá los mismos resultados.

    Dicho esto, al construir un SELECT ... JOIN, especialmente uno que incluye LEFT JOINs, he encontrado que tiene sentido considerar que el tercer JOIN se une a la nueva tabla con los resultados del primer JOIN, el cuarto ÚNASE para unir los resultados de la segunda JOIN, y así sucesivamente.

    Más raramente, el orden especificado puede influir en el comportamiento del optimizador de consultas, debido a la forma en que influye en la heurística.

  3. No. La forma en que se compila la consulta requiere que las empresas y los usuarios tengan una compañía, jobs tiene un ID de usuario y un jobid y useraccount tiene un ID de usuario. Sin embargo, solo una de las empresas o necesita un userid para que JOIN funcione.

  4. La cláusula WHERE está filtrando el resultado completo, es decir, todas las columnas JOINed, utilizando una columna proporcionada por la tabla de trabajos.

+0

"SQL no define el 'orden' en el que se realizan las INSCRIPCIONES" es falso. Consulte https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html en "Los ejemplos anteriores demuestran estos puntos:" –

+0

Creo que ese vínculo no está claro al demostrar su punto. Sin embargo, escribí esa respuesta hace casi 10 años, así que no recuerdo por qué dije eso. Pero puedo teorizar que eso es lo que entendí que significaba el estándar SQL. – staticsan

0

VER http://dev.mysql.com/doc/refman/5.0/en/join.html

y empezar a leer aquí:


Ingreso procesar los cambios en MySQL 5.0.12

A partir de MySQL 5.0.12, natural se une y se une con USING, incluidas las variantes de unión externa, se procesan según el estándar SQL: 2003. El objetivo era alinear la sintaxis y la semántica de MySQL con respecto a NATURAL JOIN y JOIN ... USING según SQL: 2003. Sin embargo, estos cambios en el procesamiento de combinación pueden dar como resultado columnas de salida diferentes para algunas combinaciones. Además, algunas consultas que parecían funcionar correctamente en versiones anteriores deben reescribirse para cumplir con el estándar.

Estos cambios tienen cinco aspectos principales:

  • la forma en que MySQL determina las columnas de resultados de NATURAL o el uso de operaciones de combinación (y así el resultado de la totalidad de la cláusula FROM).

  • Expansión de SELECT * y SELECT tbl_name. * En una lista de columnas seleccionadas.

  • Resolución de nombres de columnas en uniones NATURALES o UTILIZANDO.

  • Transformación de NATURAL o USING se une a JOIN ... ON.

  • Resolución de nombres de columnas en la condición ON de un JOIN ... ON.

9

No puedo responder el bit sobre la sintaxis de USING. Eso es raro. Nunca lo había visto antes, siempre había usado una cláusula ON.

Pero lo que puedo le dirá es que el orden de las operaciones de unión se determina de forma dinámica por el optimizador de consultas cuando se construye su plan de consulta, sobre la base de un sistema de heurísticas de optimización, algunos de los cuales son:

  1. ¿El JOIN se realiza en un campo de clave principal? Si es así, esto tiene alta prioridad en el plan de consulta.

  2. ¿El JOIN se realiza en un campo de clave externa? Esto también tiene una alta prioridad.

  3. ¿Existe un índice en el campo unido? Si es así, topa con la prioridad.

  4. ¿Se realiza una operación JOIN en un campo en la cláusula WHERE? ¿Se puede evaluar la expresión de la cláusula WHERE examinando el índice (en lugar de realizar un escaneo de tabla)? Esta es una oportunidad de optimización importante , por lo que obtiene un aumento de prioridad importante.

  5. ¿Cuál es la cardinalidad de la columna unida? Las columnas con alta cardinalidad brindan al optimizador más oportunidades para discriminar contra coincidencias falsas (aquellas que no satisfacen la cláusula WHERE o la cláusula ON), por lo que las uniones de alta cardinalidad generalmente se procesan antes de que se unan las uniones de baja cardinalidad.

  6. ¿Cuántas filas reales hay en la tabla unida? Unirse contra una tabla con solo 100 valores va a crear menos explosión de datos que unirse contra una tabla con diez millones de filas.

De todos modos ... el punto es ... hay MUCHAS variables que entran en el plan de ejecución de la consulta. Si desea ver cómo MySQL optimiza sus consultas, use la sintaxis EXPLAIN.

Y aquí es un buen artículo para leer:

http://www.informit.com/articles/article.aspx?p=377652


en Edit:

para responder a su cuarta pregunta: ¿Usted no se está consultando la tabla "empresas". Está consultando el producto cruzado unido de ALL cuatro tablas en sus cláusulas FROM y USING.

El alias "j.jobid" es simplemente el nombre completo de una de las columnas de esa colección de tablas unidas.

+0

¿Es realmente un producto cruzado? Pensé SELECCIONAR * DESDE table_a JOIN table_b USING (common_column) produciría todas las filas de table_a que tenían una coincidencia en cualquier fila del campo common_column de table_b? Es probable que sea menor que n filas. ¿No devolvería un producto cruzado n x m muchas filas? –

+0

Lo siento. No sé nada sobre la sintaxis de USO, por lo que no puedo comentar cómo funcionaría. El comentario de "producto cruzado" solo se refería a las uniones en general, que tienen la capacidad de crear una explosión combinatoria de tuplas, que es la razón por la cual el optimizador tiene en cuenta la cardinalidad. – benjismith

+0

ÍNDICE = ¿Siempre está bien? –

0

No estoy seguro acerca de la EN vs utilizando parte (aunque esto website dice que son los mismos)

En cuanto al orden de las preguntas, su puesta en práctica en su totalidad (y probablemente consulta) específico. Es muy probable que MYSQL elija un pedido al compilar la solicitud. Si desea aplicar un orden determinado que tendría que 'nido' sus consultas:

SELECT c.* 
FROM companies AS c 
    JOIN (SELECT * FROM users AS u 
     JOIN (SELECT * FROM jobs AS j USING(userid) 
       JOIN useraccounts AS us USING(userid) 
       WHERE j.jobid = 123) 
    ) 

como para la parte 4: la cláusula donde los límites de lo que las filas de la tabla de puestos de trabajo son elegibles para ser unidos sucesivamente. Por lo tanto, si hay filas que se unirían debido a los ID de usuario coincidentes pero no tienen el ID de trabajo correcto, se omitirán.

0

1) El uso no es exactamente el mismo que el, pero es corta mano donde ambas tablas tienen una columna con el mismo nombre que se están uniendo en ... ver: http://www.java2s.com/Tutorial/MySQL/0100__Table-Join/ThekeywordUSINGcanbeusedasareplacementfortheONkeywordduringthetableJoins.htm

Es más difícil de leer en mi opinión, así que iría deletreando las uniones.

3) No está claro a partir de esta consulta, pero supongo que no.

2) Suponiendo que se están uniendo a través de las otras tablas (no todos directamente en companyies) el orden en esta consulta no importa ... ver comparaciones siguientes:

original del:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u USING(companyid) 
    JOIN jobs AS j USING(userid) 
    JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123 

lo que creo que probablemente es lo que sugiere:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid 
    JOIN jobs AS j on j.userid = u.userid 
    JOIN useraccounts AS us on us.userid = u.userid 
WHERE j.jobid = 123 

Usted co uld cambia tus líneas uniendo empleos & usuarios aquí.

Lo que se vería como si todo se unió a la compañía:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid 
    JOIN jobs AS j on j.userid = c.userid 
    JOIN useraccounts AS us on us.userid = c.userid 
WHERE j.jobid = 123 

Esto no tiene ningún sentido lógico ... a menos que cada usuario tiene su propia compañía.

4.) La magia de SQL es que sólo se puede mostrar ciertas columnas, pero todos ellos son la de clasificación y filtrado ...

que ya envió

SELECT c.*, j.jobid.... 

se podía ver claramente en qué se estaba filtrando, pero al servidor de base de datos no le importa si imprime una fila o no para filtrar.

0

Aquí es una respuesta más detallada sobre JOIN precedencia. En su caso, los JOIN s son todos conmutativos. Probemos uno donde no lo sean.

Construir esquema:

CREATE TABLE users (
    name text 
); 

CREATE TABLE orders (
    order_id text, 
    user_name text 
); 

CREATE TABLE shipments (
    order_id text, 
    fulfiller text 
); 

Añadir datos:

INSERT INTO users VALUES ('Bob'), ('Mary'); 

INSERT INTO orders VALUES ('order1', 'Bob'); 

INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary'); 

Ejecutar consulta:

SELECT * 
    FROM users 
     LEFT OUTER JOIN orders 
     ON orders.user_name = users.name 
     JOIN shipments 
     ON shipments.order_id = orders.order_id 

Resultado:

Sólo la fila Bob se devuelve

Análisis:

En esta consulta la LEFT OUTER JOIN se evaluó primero y el JOIN se evaluó en el resultado compuesto de la LEFT OUTER JOIN.

Segunda consulta:

SELECT * 
    FROM users 
     LEFT OUTER JOIN (
     orders 
     JOIN shipments 
     ON shipments.order_id = orders.order_id) 
     ON orders.user_name = users.name 

Resultado:

Una fila de Bob (con los datos de cumplimiento) y una fila para María con nulos para los datos de cumplimiento.

Análisis:

El paréntesis cambió el orden de evaluación.


más documentación de MySQL está en https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html

Cuestiones relacionadas