2012-03-29 9 views
12

Mi google-fu y so-fu me están fallando aquí, así que también podría preguntar.TSQL: ¿Cuál es el orden correcto para unir tablas?

Tengo muchas consultas con varias combinaciones en ellas.

Dentro de una consulta, estoy uniendo encabezado/elemento/detalles, así como buscar varios bits de información para estos registros.

Al unirme, trato de mantener las cosas en orden de cómo se relacionan. Por ejemplo, mi encabezado tiene dos tablas de búsqueda, así que me uniré a ellas antes de unirme a mi tabla de elementos.

¿Es correcto?

¿Es mejor unirse a tablas más grandes antes de las tablas de búsqueda? ¿O viceversa?

¿Debo usar una sugerencia de loop cuando me uno a tablas pequeñas, y una sugerencia de merge cuando me una a openrowsets?

Estoy seguro de que la respuesta es "depende", pero algunas pautas generales para unir de manera efectiva y eficiente serían muy útiles. ¡Gracias!

+0

En la mayoría de los casos, no debería necesitar especificar el tipo de combinación (merge/loop/hash). Si lo hace, probablemente existan problemas subyacentes que deberían resolverse en lugar de la curita de unión. –

+2

A menos que sepa muy bien lo que está haciendo y comprenda los planes de ejecución de consultas, NUNCA use sugerencias de consulta. – JotaBe

Respuesta

12

EDITAR: Según sus preguntas (y el comentario de Kirk Woll), debe comprender que el order of your joins is aesthetic, and does not directly impact the resulting execution plan. El optimizador de consultas realizará las uniones en el orden más eficiente y utilizará la operación de combinación apropiada la mayor parte del tiempo sin necesidad de sugerencias.

Cuando se trata de la estética de su orden de unión, esto es un poco subjetivo, pero yo diría que unir sus tablas en cualquier orden tiene sentido lógico al leer la consulta ... si comienza con un @HeaderId, comenzar con esa mesa, y luego JOIN a las mesas de los niños:

FROM 
    Header h 
    JOIN Items i ON h.HeaderId = i.HeaderId 
    JOIN Details d ON i.ItemId = d.ItemId 
WHERE 
    h.HeaderId = @HeaderId 

embargo, si inició la consulta con un @DetailId, me uniría en el orden opuesto.

FROM 
    Details d 
    JOIN Items i ON d.ItemId = i.ItemId 
    JOIN Header h ON i.HeaderId = h.HeaderId 
WHERE 
    d.DetailId = @DetailId 

Sin embargo, eso es subjetivo y solo es mi preferencia personal.

Se vuelve menos subjetivo cuando empiezas a incluir OUTER JOIN s ... intenta estructurar tu consulta para evitar cualquier RIGHT OUTER JOIN s, y en su lugar usa LEFT OUTER JOIN 's.

No use consejos de unión por defecto ... de hecho, casi nunca los usará. El optimizador de consultas hace un muy buen trabajo al elegir el plan de ejecución óptimo. Solo he encontrado una sola instancia en la que necesitaba proporcionar una sugerencia de combinación para mejorar el plan ... esto ayudó drásticamente al servidor en el que se estaba ejecutando la consulta en ese momento, pero cuando la base de datos se migró a un servidor diferente, mi sugerencia de unión destruyó el rendimiento de la consulta. Por lo tanto, para reiterar, generalmente es una mala idea proporcionar consejos para unirse.

+1

¿Quizás el OP no sepa que la orden de unión es irrelevante para el plan de ejecución y es puramente estética? –

+0

@KirkWoll Ese es un muy buen punto que pasé por alto ... Lo aclararé en mi respuesta. –

+0

@Kirk, eso es exactamente por lo que estoy preguntando. El orden no es relevante en absoluto? – IronicMuffin

0

El orden es en gran medida [1] estético, pero creo que es útil tener una convención para el orden de las tablas y los términos en las condiciones de encendido, para evitar confusiones.

Las sugerencias de consulta son solo para casos excepcionales, y aunque puede encontrar situaciones en las que necesite usarlas (generalmente sacrificando el rendimiento para problemas de simultaneidad reducidos) siempre debe intentar encontrar una forma más robusta para solucionar el problema.

[1] Sé de un caso en el que el orden sí importa:

CREATE TABLE A (
    id int IDENTITY PRIMARY KEY, 
    name varchar 
); 

CREATE TABLE B (
    id int IDENTITY PRIMARY KEY, 
    a_id int FOREIGN KEY REFERENCES A (id), 
    name varchar 
); 

SELECT * 
FROM A 
INNER LOOP JOIN B on A.id = B.a_id; 

SELECT * 
FROM B 
INNER LOOP JOIN A on A.id = B.a_id; 

El primer selecto hace dos exploraciones de índices, el segundo hace una exploración y una búsqueda. Esta es otra buena razón para evitar sugerencias.

Cuestiones relacionadas