2009-02-04 5 views
73

Acabo de tener una consulta bastante compleja con la que estaba trabajando y me tomó 8 segundos ejecutarla. EXPLAIN mostraba un orden de tabla extraño y mis índices no se usaban todos, incluso con la sugerencia FORCE INDEX. Encontré la palabra clave de combinación STRAIGHT_JOIN y comencé a reemplazar algunas de mis palabras clave INNER JOIN con ella. Noté una considerable mejora en la velocidad. Eventualmente acabo de reemplazar todas mis palabras clave INNER JOIN con STRAIGHT_JOIN para esta consulta y ahora se ejecuta en .01 segundos.Cuándo usar STRAIGHT_JOIN con MySQL

Mi pregunta es ¿cuándo se utiliza STRAIGHT_JOIN y cuándo se utiliza INNER JOIN? ¿Hay alguna razón para no usar STRAIGHT_JOIN si está escribiendo buenas consultas?

Respuesta

69

yo no recomendaría el uso de STRAIGHT_JOIN sin una buena razón. Mi propia experiencia es que el optimizador de consultas MySQL elige un plan de consulta pobre con más frecuencia de la que me gustaría, pero no con la suficiente frecuencia como para omitirlo en general, que es lo que harías si siempre usaras STRAIGHT_JOIN.

Mi recomendación es dejar todas las consultas tan regular uniones. Si descubre que una consulta está utilizando un plan de consulta subóptimo, le sugiero primero intentar reescribir o reestructurar la consulta un poco para ver si el optimizador elegirá un mejor plan de consulta. Además, al menos para innodb, asegúrese de que las estadísticas del índice no estén desactualizadas (ANALYZE TABLE). Eso puede hacer que el optimizador elija un plan de consulta pobre. Las sugerencias del optimizador generalmente deberían ser su último recurso.

Otra razón para no usar sugerencias de consulta es que su distribución de datos puede cambiar con el tiempo, o su selectividad índice puede cambiar, etc, como su mesa crece. Sus sugerencias de consulta que son óptimas ahora, pueden volverse subóptimas con el tiempo. Pero el optimizador no podrá adaptar el plan de consulta debido a sus sugerencias ahora desactualizadas. Te mantienes más flexible si permites que el optimizador tome las decisiones.

+1

Gracias, gran explicación. – Greg

+27

Esta respuesta en realidad no explica ** cuándo usar ** 'straight_join'. – Pacerier

16

MySQL no es bueno en necessarilly elegir el orden de combinación en consultas complejas. Al especificar una consulta compleja como un straight_join, la consulta ejecuta las uniones en el orden en que se especifican. Al colocar la tabla como el denominador menos común primero y especificar straight_join, puede mejorar el rendimiento de la consulta.

19

De MySQL JOIN reference:.

"STRAIGHT_JOIN es similar a JOIN, excepto que la tabla de la izquierda se lee siempre antes de la tabla de la derecha Esto puede ser usado para aquellos (pocos) casos en los que el optimizador de join pone las tablas en la orden incorrecta ".

+10

Gracias, pero ya leí el manual de MySQL. Esperando más explicaciones. – Greg

10

STRAIGHT_JOIN, usando esta cláusula, puede controlar el orden JOIN: qué tabla se escanea en el bucle externo y cuál se encuentra en el bucle interno.

+0

¿Qué son el lazo externo y el lazo interno? –

7

Aquí hay un escenario que surgió recientemente en el trabajo.

considerar tres tablas, A, B, C.

A tiene 3.000 filas; B tiene 300,000,000 filas; y C tiene 2,000 filas.

Las claves externas se definen: B (A_ID), B (C_ID).

Supongamos que tenemos una consulta que tiene el siguiente aspecto:

select a.id, c.id 
from a 
join b on b.a_id = a.id 
join c on c.id = b.c_id 

En mi experiencia, MySQL puede optar por ir C -> B -> A en este caso. C es más pequeño que A y B es enorme, y todos son equijoins.

El problema es que MySQL no tiene necesariamente en cuenta el tamaño de la intersección entre (C.id y B.c_id) vs (A.id y B.a_id). Si la unión entre B y C devuelve tantas filas como B, entonces es una opción muy pobre; si comenzar con A hubiera filtrado B a tantas filas como A, entonces habría sido una opción mucho mejor.

Por lo general, desea realizar sus uniones en una orden que minimice el número de filas en el conjunto resultante. Entonces, comenzar con una tabla pequeña y unir de tal manera que la unión resultante también sea pequeña, es ideal. Las cosas van en forma de pera si se comienza con una pequeña mesa y unirla a una mesa más grande termina tan grande como la gran mesa.

Sin embargo, son estadísticas dependientes. Si la distribución de datos cambia, el cálculo puede cambiar. También depende de los detalles de implementación del mecanismo de combinación.

+0

¿Cómo usaría la unión directa para solucionar el problema? – Hannele

+0

@Hannele 'straight_join' evalúa la tabla de la izquierda antes que la derecha. Entonces, si quieres pasar de 'A -> B -> C' en mi ejemplo, la primera palabra clave' join' podría reemplazarse por 'straight_join'. –

+0

Ah limpio. Sería útil incluir eso como un ejemplo en su respuesta :) – Hannele

-4
--use 120s, 18 million data 
    explain SELECT DISTINCT d.taid 
    FROM tvassist_recommend_list_everyday_diverse d, tvassist_taid_all t 
    WHERE d.taid = t.taid 
     AND t.client_version >= '21004007' 
     AND t.utdid IS NOT NULL 
     AND d.recommend_day = '20170403' 
    LIMIT 0, 10000 

--use 3.6s repalce by straight join 
explain SELECT DISTINCT d.taid 
    FROM tvassist_recommend_list_everyday_diverse d 
    STRAIGHT_JOIN 
     tvassist_taid_all t on d.taid = t.taid 
    WHERE 
    t.client_version >= '21004007' 
     AND d.recommend_day = '20170403' 

     AND t.utdid IS NOT NULL 
    LIMIT 0, 10000 
+0

Esto no le da información suficiente para determinar cuándo son apropiadas las uniones rectas. – Hannele

2

voy a decir por qué tuve que usar STRAIGHT_JOIN:

  • que tenían un problemarendimiento con una consulta.
  • Simplificando la consulta, la consulta fue repentinamente más eficiente
  • Tratando de averiguar qué parte específica estaba trayendo el problema, simplemente no pude. (2 izquierda une eran lentos, y cada uno era independientemente rápido)
  • entonces ejecuta el de explicar con tanto consulta lenta y rápida (addind uno de la izquierda se une)
  • Sorprendentemente, MySQL cambiado por completo las órdenes entre el JOIN 2 consultas.

Por lo tanto obligué a una de las uniones a straight_join a FORCE la unión anterior para leer primero. ¡Esto impidió que MySQL cambiara el orden de ejecución y funcionó como un amuleto!

Cuestiones relacionadas