Creé un comando SQL que usa INNER JOIN en 9 tablas, de todos modos este comando lleva mucho tiempo (más de cinco minutos). Así que mi gente me sugirió cambiar INNER JOIN a LEFT JOIN porque el rendimiento de LEFT JOIN es mejor, a pesar de lo que sé. Después de cambiarlo, la velocidad de consulta mejoró significativamente.
Me gustaría saber por qué LEFT JOIN es más rápido que INNER JOIN.
Mi comando SQL se ve a continuación:
SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN D
y así sucesivamente
Actualización: esto es breve de mi esquema.
FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
ON a.CompanyCd = b.CompanyCd
AND a.SPRNo = b.SPRNo
AND a.SuffixNo = b.SuffixNo
AND a.dnno = b.dnno
INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
ON a.CompanyCd = h.CompanyCd
AND a.sprno = h.AcctSPRNo
INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
ON c.CompanyCd = h.CompanyCd
AND c.FSlipNo = h.FSlipNo
AND c.FSlipSuffix = h.FSlipSuffix
INNER JOIN coMappingExpParty d -- NO PK AND FK
ON c.CompanyCd = d.CompanyCd
AND c.CountryCd = d.CountryCd
INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
ON b.CompanyCd = e.CompanyCd
AND b.ProductSalesCd = e.ProductSalesCd
LEFT JOIN coUOM i -- PK = UOMId
ON h.UOMId = i.UOMId
INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
ON a.CompanyCd = j.CompanyCd
AND b.BFStatus = j.BFStatus
AND b.ProductSalesCd = j.ProductSalesCd
INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
ON e.ProductGroup1Cd = g1.ProductGroup1Cd
INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
ON e.ProductGroup1Cd = g2.ProductGroup1Cd
sql
sql-server
performance
Anónimo
fuente
fuente
coUOM
? Si no, puede usar una semiunión. En caso afirmativo, podría utilizarloUNION
como alternativa. Publicar solo suFROM
cláusula es información inadecuada aquí.Respuestas:
A no
LEFT JOIN
es absolutamente más rápido que unINNER JOIN
. De hecho, es más lento; por definición, una unión externa (LEFT JOIN
oRIGHT JOIN
) tiene que hacer todo el trabajo de unINNER JOIN
plus y el trabajo adicional de extender los resultados nulo. También se esperaría que devuelva más filas, aumentando aún más el tiempo total de ejecución simplemente debido al mayor tamaño del conjunto de resultados.(¡Incluso si a
LEFT JOIN
fuera más rápido en situaciones específicas debido a una confluencia de factores difícil de imaginar, no es funcionalmente equivalente a unINNER JOIN
, por lo que no puede simplemente reemplazar todas las instancias de una por la otra!)Lo más probable es que sus problemas de rendimiento se encuentren en otra parte, como no tener una clave candidata o una clave externa indexada correctamente. Hay mucho que unir a 9 tablas, por lo que la desaceleración podría ser literalmente en casi cualquier lugar. Si publica su esquema, es posible que podamos brindarle más detalles.
Editar:
Al reflexionar más sobre esto, podría pensar en una circunstancia bajo la cual un
LEFT JOIN
podría ser más rápido que unINNER JOIN
, y es cuando:Considere este ejemplo:
Si ejecuta esto y ve el plan de ejecución, verá que la
INNER JOIN
consulta realmente cuesta más que elLEFT JOIN
, porque satisface los dos criterios anteriores. Esto se debe a que SQL Server quiere hacer una coincidencia hash para elINNER JOIN
, pero hace bucles anidados para elLEFT JOIN
; el primero es normalmente mucho más rápido, pero dado que el número de filas es muy pequeño y no hay índice para usar, la operación de hash resulta ser la parte más costosa de la consulta.Puede ver el mismo efecto escribiendo un programa en su lenguaje de programación favorito para realizar una gran cantidad de búsquedas en una lista con 5 elementos, frente a una tabla hash con 5 elementos. Debido al tamaño, la versión de la tabla hash es realmente más lenta. Pero aumente a 50 elementos, o 5000 elementos, y la versión de la lista se ralentiza, porque es O (N) frente a O (1) para la tabla hash.
Pero cambie esta consulta para que esté en la
ID
columna en lugar deName
y verá una historia muy diferente. En ese caso, realiza bucles anidados para ambas consultas, pero laINNER JOIN
versión puede reemplazar uno de los escaneos de índice agrupados con una búsqueda, lo que significa que literalmente será un orden de magnitud más rápido con un gran número de filas.Entonces, la conclusión es más o menos lo que mencioné en varios párrafos anteriores; esto es casi seguro un problema de indexación o cobertura de índice, posiblemente combinado con una o más tablas muy pequeñas. Esas son las únicas circunstancias en las que SQL Server a veces puede elegir un plan de ejecución peor para un
INNER JOIN
que aLEFT JOIN
.fuente
Hay un escenario importante que puede llevar a que una unión externa sea más rápida que una unión interna que aún no se ha discutido.
Cuando se usa una combinación externa, el optimizador siempre es libre de eliminar la tabla externa unida del plan de ejecución si las columnas de combinación son el PK de la tabla externa, y ninguna de las columnas de la tabla externa está referenciada fuera de la propia combinación externa. Por ejemplo,
SELECT A.* FROM A LEFT OUTER JOIN B ON A.KEY=B.KEY
B.KEY es la PK para B. Tanto Oracle (creo que estaba usando la versión 10) como Sql Server (usé 2008 R2) eliminan la tabla B del plan de ejecución.Lo mismo no es necesariamente cierto para una unión interna:
SELECT A.* FROM A INNER JOIN B ON A.KEY=B.KEY
puede o no requerir B en el plan de ejecución dependiendo de las restricciones que existan.Si A.KEY es una clave externa anulable que hace referencia a B.KEY, entonces el optimizador no puede eliminar B del plan porque debe confirmar que existe una fila B para cada fila A.
Si A.KEY es una clave foránea obligatoria que hace referencia a B.KEY, entonces el optimizador es libre de eliminar B del plan porque las restricciones garantizan la existencia de la fila. Pero el hecho de que el optimizador pueda eliminar la tabla del plan no significa que lo hará. SQL Server 2008 R2 NO elimina B del plan. Oracle 10 SÍ deja caer B del plan. En este caso, es fácil ver cómo la combinación externa superará a la combinación interna en SQL Server.
Este es un ejemplo trivial, y no es práctico para una consulta independiente. ¿Por qué unirse a una mesa si no es necesario?
Pero esto podría ser una consideración de diseño muy importante al diseñar vistas. Con frecuencia se crea una vista de "hacer todo" que une todo lo que un usuario pueda necesitar relacionado con una tabla central. (Especialmente si hay usuarios ingenuos que realizan consultas ad-hoc que no entienden el modelo relacional) La vista puede incluir todas las columnas relevantes de muchas tablas. Pero los usuarios finales solo pueden acceder a las columnas de un subconjunto de las tablas dentro de la vista. Si las tablas se unen con uniones externas, entonces el optimizador puede (y lo hace) eliminar las tablas innecesarias del plan.
Es fundamental asegurarse de que la vista que utiliza combinaciones externas proporcione los resultados correctos. Como ha dicho Aaronaught: no puede sustituir ciegamente OUTER JOIN por INNER JOIN y esperar los mismos resultados. Pero hay momentos en que puede ser útil por razones de rendimiento al usar vistas.
Una última nota: no he probado el impacto en el rendimiento a la luz de lo anterior, pero en teoría parece que debería poder reemplazar de forma segura una UNIÓN INTERNA con una UNIÓN EXTERNA si también agrega la condición <FOREIGN_KEY> NO ES NULO a la cláusula where.
fuente
Si todo funciona como debería, PERO todos sabemos que todo no funciona como debería, especialmente cuando se trata del optimizador de consultas, el almacenamiento en caché del plan de consulta y las estadísticas.
Primero sugeriría reconstruir el índice y las estadísticas, luego borrar el caché del plan de consulta solo para asegurarme de que eso no esté arruinando las cosas. Sin embargo, he experimentado problemas incluso cuando eso está hecho.
He experimentado algunos casos en los que una unión izquierda ha sido más rápida que una unión interna.
La razón subyacente es esta: si tiene dos tablas y se une en una columna con un índice (en ambas tablas). La unión interna producirá el mismo resultado sin importar si realiza un bucle sobre las entradas en el índice en la tabla uno y coincide con el índice en la tabla dos como si hiciera lo contrario: repita las entradas en el índice en la tabla dos y coincida con el índice en la tabla uno. El problema es que cuando tiene estadísticas engañosas, el optimizador de consultas usará las estadísticas del índice para encontrar la tabla con menos entradas coincidentes (según sus otros criterios). Si tiene dos tablas con 1 millón en cada una, en la tabla uno tiene 10 filas coincidentes y en la tabla dos tiene 100000 filas coincidentes. La mejor manera sería hacer una exploración de índice en la tabla uno y hacer coincidir 10 veces en la tabla dos. Lo contrario sería una exploración de índice que recorre más de 100000 filas e intenta coincidir 100000 veces y solo 10 tienen éxito. Entonces, si las estadísticas no son correctas, el optimizador puede elegir la tabla y el índice incorrectos para realizar un bucle.
Si el optimizador elige optimizar la unión izquierda en el orden en que está escrito, funcionará mejor que la unión interna.
PERO, el optimizador también puede optimizar una unión izquierda subóptimamente como una semiunión izquierda. Para que elija el que desee, puede usar la sugerencia de orden de fuerza.
fuente
Pruebe ambas consultas (la que tiene la unión interna y la izquierda) con
OPTION (FORCE ORDER)
al final y publique los resultados.OPTION (FORCE ORDER)
es una sugerencia de consulta que obliga al optimizador a crear el plan de ejecución con el orden de combinación que proporcionó en la consulta.Si
INNER JOIN
comienza a funcionar tan rápido como seaLEFT JOIN
, es porque:INNER JOIN
s, el orden de unión no importa. Esto le da libertad al optimizador de consultas para ordenar las uniones como mejor le parezca, por lo que el problema podría depender del optimizador.LEFT JOIN
, ese no es el caso porque cambiar el orden de unión alterará los resultados de la consulta. Esto significa que el motor debe seguir el orden de unión que proporcionó en la consulta, que podría ser mejor que el optimizado.No sé si esto responde a su pregunta, pero una vez estuve en un proyecto que presentaba consultas muy complejas que realizaban cálculos, lo que desordenó completamente el optimizador. Tuvimos casos en los
FORCE ORDER
que a reduciría el tiempo de ejecución de una consulta de 5 minutos a 10 segundos.fuente
He hecho una serie de comparaciones entre las uniones externas e internas izquierdas y no he podido encontrar una diferencia constante. Hay muchas variables Estoy trabajando en una base de datos de informes con miles de tablas, muchas con una gran cantidad de campos, muchos cambios a lo largo del tiempo (versiones del proveedor y flujo de trabajo local). No es posible crear todas las combinaciones de índices de cobertura para satisfacer las necesidades de una variedad tan amplia de consultas y manejar datos históricos. He visto consultas internas que matan el rendimiento del servidor porque dos tablas grandes (de millones a decenas de millones de filas) están unidas internamente, ambas extraen una gran cantidad de campos y no existe un índice de cobertura.
Sin embargo, el mayor problema no parece aparecer en las discusiones anteriores. Tal vez su base de datos esté bien diseñada con disparadores y procesamiento de transacciones bien diseñado para garantizar buenos datos. El mío frecuentemente tiene valores NULL donde no se esperan. Sí, las definiciones de tabla podrían imponer valores nulos, pero esa no es una opción en mi entorno.
Entonces, la pregunta es ... ¿diseña su consulta solo para la velocidad, una prioridad más alta para el procesamiento de transacciones que ejecuta el mismo código miles de veces por minuto. ¿O busca la precisión que proporcionará una unión externa izquierda? Recuerde que las uniones internas deben encontrar coincidencias en ambos lados, por lo que un NULL inesperado no solo eliminará datos de las dos tablas, sino posiblemente filas enteras de información. Y sucede tan bien, no hay mensajes de error.
Puede ser muy rápido ya que obtener el 90% de los datos necesarios y no descubrir que las uniones internas han eliminado silenciosamente la información. A veces, las uniones internas pueden ser más rápidas, pero no creo que nadie haga esa suposición a menos que hayan revisado el plan de ejecución. La velocidad es importante, pero la precisión es más importante.
fuente
Es más probable que sus problemas de rendimiento se deban a la cantidad de uniones que está haciendo y si las columnas a las que se une tienen índices o no.
En el peor de los casos, podría estar haciendo fácilmente 9 escaneos de tabla completa para cada combinación.
fuente
Las uniones externas pueden ofrecer un rendimiento superior cuando se usan en vistas.
Supongamos que tiene una consulta que involucra una vista, y esa vista se compone de 10 tablas unidas. Digamos que su consulta solo utiliza columnas de 3 de esas 10 tablas.
Si esas 10 tablas se hubieran unido internamente, entonces el optimizador de consultas tendría que unirlas todas, aunque su consulta en sí no necesita 7 de cada 10 tablas. Esto se debe a que las uniones internas pueden filtrar los datos, haciéndolos esenciales para el cálculo.
Si esas 10 tablas se hubieran unido externamente, el optimizador de consultas solo uniría las que fueran necesarias: 3 de cada 10 en este caso. Esto se debe a que las uniones en sí mismas ya no filtran los datos y, por lo tanto, se pueden omitir las uniones no utilizadas.
Fuente: http://www.sqlservercentral.com/blogs/sql_coach/2010/07/29/poor-little-misunderstood-views/
fuente
Encontré algo interesante en el servidor SQL al verificar si las combinaciones internas son más rápidas que las combinaciones izquierdas.
Si no incluye los elementos de la tabla unida a la izquierda, en la instrucción de selección, la unión izquierda será más rápida que la misma consulta con la unión interna.
Si incluye la tabla unida a la izquierda en la instrucción select, la unión interna con la misma consulta fue igual o más rápida que la unión izquierda.
fuente
Según mis comparaciones, encuentro que tienen exactamente el mismo plan de ejecución. Hay tres escenarios:
Si y cuando devuelven los mismos resultados, tienen la misma velocidad. Sin embargo, debemos tener en cuenta que no son las mismas consultas y que LEFT JOIN posiblemente devolverá más resultados (cuando no se cumplan algunas condiciones de ENCENDIDO) --- por eso suele ser más lento.
Cuando la tabla principal (la primera no constante en el plan de ejecución) tiene una condición restrictiva (WHERE id =?) Y la condición ON correspondiente está en un valor NULL, la tabla "derecha" no está unida --- esto es cuando IZQUIERDA UNIRSE es más rápido.
Como se discutió en el punto 1, generalmente INNER JOIN es más restrictivo y devuelve menos resultados y, por lo tanto, es más rápido.
Ambos usan (los mismos) índices.
fuente