Aquí hay un escenario que surgió recientemente en el trabajo.
Considere tres tablas, A, B, C.
A tiene 3000 filas; B tiene 300.000.000 filas; y C tiene 2000 filas.
Se definen claves externas: B (a_id), B (c_id).
Suponga que tiene una consulta similar a esta:
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 necesariamente tiene 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 muy mala elección; si comenzar con A hubiera filtrado B a tantas filas como A, entonces habría sido una opción mucho mejor. straight_join
podría usarse para forzar este orden así:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
Ahora a
debe unirse antes b
.
Por lo general, desea realizar las uniones en un orden que minimice el número de filas en el conjunto resultante. Entonces, comenzar con una mesa pequeña y unir de 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 mesa pequeña y se une a una mesa más grande y termina tan grande como la mesa grande.
Sin embargo, depende de las estadísticas. Si cambia la distribución de datos, el cálculo puede cambiar. También depende de los detalles de implementación del mecanismo de combinación.
Los peores casos que he visto para MySQL en los que todos los straight_join
indicios de índice, excepto los obligatorios o agresivos, son consultas que paginan una gran cantidad de datos en un orden de clasificación estricto con filtrado ligero. MySQL prefiere usar índices para cualquier filtro y se une sobre ordenaciones; esto tiene sentido porque la mayoría de las personas no están tratando de ordenar toda la base de datos, sino que tienen un subconjunto limitado de filas que responden a la consulta, y ordenar un subconjunto limitado es mucho más rápido que filtrar toda la tabla, sin importar si está ordenada o no. En este caso, poner una combinación recta inmediatamente después de la tabla que tenía la columna indexada que quería ordenar en cosas fijas.
straight_join
.