sql >> Base de Datos >  >> RDS >> Database

Su guía definitiva para SQL Join:INNER JOIN – Parte 1

Unión interna, unión externa, unión cruzada? ¿Qué da?

Es una pregunta válida. Una vez vi un código de Visual Basic con códigos T-SQL incrustados. El código de VB recupera los registros de la tabla con varias instrucciones SELECT, una SELECT * por tabla. Luego, combina varios conjuntos de resultados en un conjunto de registros. ¿Absurdo?

Para los jóvenes desarrolladores que lo hicieron, no fue así. Pero cuando me pidieron que evaluara por qué el sistema estaba lento, ese tema fue lo primero que me llamó la atención. Así es. Nunca han oído hablar de las uniones SQL. Para ser justos con ellos, fueron honestos y abiertos a sugerencias.

¿Cómo describe las uniones SQL? Quizás recuerdes una canción:Imagine de John Lennon:

Puedes decir que soy un soñador, pero no soy el único.

Espero que algún día te unas a nosotros y el mundo sea uno solo.

En el contexto de la canción, unir es unir. En una base de datos SQL, combinar registros de 2 o más tablas en un conjunto de resultados forma una unión .

Este artículo es el comienzo de una serie de 3 partes que habla sobre combinaciones SQL:

  • UNIÓN INTERNA
  • UNIÓN EXTERNA, que incluye IZQUIERDA, DERECHA y COMPLETA
  • UNIÓN CRUZADA

Pero antes de comenzar a discutir INNER JOIN, describamos las uniones en general.

Más sobre SQL JOIN

Las uniones aparecen justo después de la cláusula FROM. En su forma más simple, parece usar el estándar SQL-92:

FROM <table source> [<alias1>]
<join type> JOIN <table source> [<alias2>] [ON <join condition>] 
[<join type> JOIN <table source> [<alias3>] [ON <join condition>]
<join type> JOIN <table source> [<aliasN>] [ON <join condition>]]
[WHERE <condition>]

Describamos las cosas cotidianas que rodean a JOIN.

Fuentes de tabla

Puede agregar hasta 256 fuentes de tablas, según Microsoft. Por supuesto, depende de los recursos de su servidor. Nunca me he unido a más de 10 mesas en mi vida, por no hablar de 256. De todos modos, las fuentes de la mesa pueden ser cualquiera de las siguientes:

  • Mesa
  • Ver
  • Sinónimo de tabla o vista
  • Variable de tabla
  • Función con valores de tabla
  • Tabla derivada

Alias ​​de tabla

Un alias es opcional, pero acorta su código y minimiza la escritura. También lo ayuda a evitar errores cuando existe un nombre de columna en dos o más tablas utilizadas en SELECCIONAR, ACTUALIZAR, INSERTAR o ELIMINAR. También agrega claridad a su código. Es opcional, pero recomendaría usar alias. (A menos que le guste escribir las fuentes de la tabla por nombre).

Condición de unión

La palabra clave ON precede a la condición de unión que puede ser una sola unión o columnas de 2 claves de las 2 tablas unidas. O puede ser una unión compuesta usando más de 2 columnas clave. Define cómo se relacionan las tablas.

Sin embargo, usamos la condición de unión solo para las uniones INNER y OUTER. Usarlo en un CROSS JOIN generará un error.

Dado que las condiciones de combinación definen las relaciones, necesitan operadores.

El operador de condición de unión más común es el operador de igualdad (=). Otros operadores como> o

SQL JOIN frente a subconsultas

La mayoría de las uniones se pueden reescribir como subconsultas y viceversa. Consulte este artículo para obtener más información sobre las subconsultas en comparación con las uniones.

Uniones y tablas derivadas

El uso de tablas derivadas en una combinación se ve así:

FROM table1 a
INNER JOIN (SELECT y.column3 from table2 x
            INNER JOIN table3 y on x.column1 = y.column1) b ON a.col1 = b.col2

Se une a partir del resultado de otra sentencia SELECT y es perfectamente válida.

Tendrá más ejemplos, pero tratemos una última cosa sobre SQL JOINS. Así es como se unen los procesos del optimizador de consultas de SQL Server.

Cómo procesa SQL Server las uniones

Para comprender cómo funciona el proceso, debe conocer los dos tipos de operaciones involucradas:

  • Operaciones lógicas corresponden a los tipos de unión utilizados en una consulta:INTERIOR, EXTERIOR o CRUZADO. Usted, como desarrollador, define esta parte del procesamiento cuando forma la consulta.
  • Operaciones físicas – Query Optimizer elige la mejor operación física aplicable para su unión. Lo mejor significa lo más rápido para producir resultados. El Plan de Ejecución de su consulta mostrará los operadores de unión física elegidos. Estas operaciones son:
    • Unión de bucle anidado. Esta operación es rápida si una de las dos tablas es pequeña y la segunda es grande e indexada. Requiere la menor cantidad de E/S con la menor cantidad de comparaciones, pero no es bueno para grandes conjuntos de resultados.
    • Fusionar Unión. Esta es la operación más rápida para conjuntos de resultados grandes y ordenados por columnas utilizadas en la unión.
    • Unión hash. El optimizador de consultas lo usa cuando el conjunto de resultados es demasiado grande para un bucle anidado y las entradas no están ordenadas para una combinación de combinación. Un hash es más eficiente que ordenarlo primero y aplicar una combinación Merge.
    • Unión adaptable. A partir de SQL Server 2017, permite la elección entre un bucle anidado o hash . El método de unión se difiere hasta que se escanea la primera entrada. Esta operación cambia dinámicamente a una unión física mejor sin volver a compilar.

¿Por qué tenemos que molestarnos con esto?

Una palabra:Rendimiento.

Una cosa es saber cómo formar consultas con combinaciones para producir resultados correctos. Otra es hacer que corra lo más rápido posible. Tienes que preocuparte más por esto si quieres una buena reputación con tus usuarios.

Entonces, ¿qué debe tener en cuenta en el Plan de Ejecución para estas operaciones lógicas?

  • Supongamos que un operador Ordenar precede a Combinar combinación . Esta operación de clasificación es costosa para tablas grandes (Figura 2). Puede solucionar esto ordenando previamente las tablas de entrada en la combinación.
  • Supongamos que hay duplicados en las tablas de entrada de una unión Merge . SQL Server escribirá los duplicados de la segunda tabla en una WorkTable en tempdb. Luego, hará las comparaciones allí. STATISTICS IO revelará las WorkTables involucradas.
  • Cuando se derraman grandes cantidades de datos en tempdb en un Hash jo en, STATISTICS IO revelará una gran lectura lógica en WorkFiles o WorkTables. También aparecerá una advertencia en el Plan de Ejecución (Figura 3). Puede aplicar dos cosas:ordenar previamente las tablas de entrada o reducir las uniones, si es posible. Como resultado, el Optimizador de consultas puede elegir otra unión física.

Sugerencias para unirse

Las sugerencias de unión son nuevas en SQL Server 2019. Cuando las usa en sus uniones, le dice al optimizador de consultas que deje de decidir qué es lo mejor para la consulta. Eres el jefe cuando se trata de la unión física a usar.

Ahora detente, justo ahí. La verdad es que el optimizador de consultas generalmente selecciona la mejor unión física para su consulta. Si no sabe lo que está haciendo, no use sugerencias para unirse.

Las posibles sugerencias que puede especificar son LOOP, MERGE, HASH o REMOTE.

No he usado sugerencias para unir, pero aquí está la sintaxis:


<join type> <join hint> JOIN <table source> [<alias>] ON <join condition>

Todo sobre INNER JOIN

INNER JOIN devuelve las filas con registros coincidentes en ambas tablas, según una condición. También es la combinación predeterminada si no especifica la palabra clave INNER:

Como puede ver, filas coincidentes de Table1 y Tabla2 se devuelven usando Key1 como condición de unión. La Tabla1 registro que tiene Key1 ='C' se excluye porque no hay registros coincidentes en Table2 .

Cada vez que formulo una consulta, mi primera opción es INNER JOIN. OUTER JOIN viene solo cuando los requisitos lo dictan.

Sintaxis de INNER JOIN

Hay dos sintaxis INNER JOIN admitidas en T-SQL:SQL-92 y SQL-89.

SQL-92 UNIÓN INTERNA

FROM <table source1> [<alias1>]
INNER JOIN <table source2> [<alias2>] ON <join condition1>
[INNER JOIN <table source3> [<alias3>] ON <join condition2>
 INNER JOIN <table sourceN> [<aliasN>] ON <join conditionN>]
[WHERE <condition>]

SQL-89 UNIÓN INTERNA

FROM <table source1> [alias1], <table source2> [alias2] [, <table source3> [alias3], <table sourceN> [aliasN]]
WHERE (<join condition1>)
[AND (<join condition2>)
AND (<join condition3>)
AND (<join conditionN>)]

¿Qué sintaxis de INNER JOIN es mejor?

La primera sintaxis de combinación que aprendí fue SQL-89. Cuando finalmente llegó SQL-92, pensé que era demasiado largo. También pensé que como el resultado era el mismo, ¿por qué molestarse en escribir más palabras clave? Un diseñador de consultas gráficas tenía el código generado SQL-92 y lo cambié de nuevo a SQL-89. Pero hoy, prefiero SQL-92 incluso si tengo que escribir más. He aquí por qué:

  • La intención del tipo de unión es clara. El próximo chico o chica que mantendrá mi código sabrá lo que se pretende en la consulta.
  • Olvidar la condición de combinación en una sintaxis SQL-92 generará un error. Mientras tanto, olvidar la condición de unión en SQL-89 se tratará como una UNIÓN CRUZADA. Si me refiero a una unión INTERNA o EXTERNA, sería un error lógico imperceptible hasta que los usuarios se quejen.
  • Las nuevas herramientas se inclinan más por SQL-92. Si alguna vez vuelvo a usar un diseñador gráfico de consultas, no tengo que cambiarlo a SQL-89. Ya no soy terco, por lo que mi ritmo cardíaco ha vuelto a la normalidad. Saludos para mí.

Las razones anteriores son mías. Puede tener sus razones por las que prefiere SQL-92 o por las que lo odia. Me pregunto cuáles son esas razones. Házmelo saber en la sección de Comentarios a continuación.

Pero no podemos terminar este artículo sin ejemplos y explicaciones.

10 ejemplos de INNER JOIN

1. Unirse a 2 mesas

Aquí hay un ejemplo de 2 tablas unidas usando INNER JOIN en la sintaxis SQL-92.

-- Display Vests, Helmets, and Light products

USE AdventureWorks
GO

SELECT
 p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory ps ON P.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE P.ProductSubcategoryID IN (25, 31, 33);  -- for vest, helmet, and light 
                                            -- product subcategories

Solo especificas las columnas que necesitas. En el ejemplo anterior, se especifican 4 columnas. Sé que es demasiado largo que SELECT *, pero ten esto en cuenta:es la mejor práctica.

Observe también el uso de alias de tabla. Tanto el Producto y Subcategoría de producto las tablas tienen una columna llamada [Nombre ]. Si no especifica el alias, se activará un error.

Mientras tanto, aquí está la sintaxis SQL-89 equivalente:

-- Display Vests, Helmets, and Light products

USE AdventureWorks
GO

SELECT
 p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p, Production.ProductSubcategory ps 
WHERE P.ProductSubcategoryID = ps.ProductSubcategoryID
AND P.ProductSubcategoryID IN (25, 31, 33);

Son iguales excepto por la condición de unión mezclada en la cláusula WHERE con una palabra clave AND. Pero bajo el capó, ¿son realmente lo mismo? Inspeccionemos el conjunto de resultados, el IO de ESTADÍSTICAS y el Plan de Ejecución.

Vea el conjunto de resultados de 9 registros:

No son solo los resultados, sino que los recursos requeridos por SQL Server también son los mismos.

Ver las lecturas lógicas:

Finalmente, el plan de ejecución revela el mismo plan de consulta para ambas consultas cuando sus QueryPlanHashes son iguales. Observe también las operaciones resaltadas en el diagrama:

Según los hallazgos, el procesamiento de consultas de SQL Server es el mismo, ya sea SQL-92 o SQL-89. Pero como dije, la claridad en SQL-92 es mucho mejor para mí.

La figura 7 también muestra una combinación de bucle anidado utilizada en el plan. ¿Por qué? El conjunto de resultados es pequeño.

2. Unirse a varias mesas

Echa un vistazo a la consulta a continuación usando 3 tablas unidas.

-- Get the total number of orders per Product Category
USE AdventureWorks
GO

SELECT
 ps.Name AS ProductSubcategory
,SUM(sod.OrderQty) AS TotalOrders
FROM Production.Product p
INNER JOIN Sales.SalesOrderDetail sod ON P.ProductID = sod.ProductID
INNER JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE soh.OrderDate BETWEEN '1/1/2014' AND '12/31/2014'
AND p.ProductSubcategoryID IN (1,2)
GROUP BY ps.Name
HAVING ps.Name IN ('Mountain Bikes', 'Road Bikes')

3. Unión compuesta

También puedes unir 2 tablas usando 2 claves para relacionarlo. Echa un vistazo a la muestra a continuación. Utiliza 2 condiciones de unión con un operador AND.

SELECT
 a.column1
,b.column1
,b.column2
FROM Table1 a
INNER JOIN Table2 b ON a.column1 = b.column1 AND a.column2 = b.column2

4. INNER JOIN Uso de una unión física de bucle anidado

En el siguiente ejemplo, el Producto la tabla tiene 9 registros, un conjunto pequeño. La tabla unida es SalesOrderDetail - un conjunto grande. El Optimizador de consultas utilizará una combinación de bucle anidado, como se muestra en la Figura 8.

USE AdventureWorks
GO

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

5. INNER JOIN Uso de una combinación física de combinación

El siguiente ejemplo utiliza una combinación de combinación porque ambas tablas de entrada están ordenadas por SalesOrderID.

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

6. INNER JOIN Usar una unión física hash

El siguiente ejemplo usará un Hash Join:

SELECT
 s.Name AS Store
,SUM(soh.TotalDue) AS TotalSales
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.Store s ON soh.SalesPersonID = s.SalesPersonID
GROUP BY s.Name

7. INNER JOIN Uso de Adaptive Physical Join

En el siguiente ejemplo, el Vendedor la tabla tiene un Índice de almacén de columnas no agrupado en el TerritoryID columna. El optimizador de consultas optó por una combinación de bucle anidado, como se muestra en la figura 11.

SELECT
sp.BusinessEntityID
,sp.SalesQuota
,st.Name AS Territory
FROM Sales.SalesPerson sp
INNER JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
WHERE sp.TerritoryID BETWEEN 1 AND 5

8. Dos formas de reescribir una subconsulta en un INNER JOIN

Considere esta declaración con una subconsulta anidada:

SELECT [SalesOrderID], [OrderDate], [ShipDate], [CustomerID]
FROM Sales.SalesOrderHeader 
WHERE [CustomerID] IN (SELECT [CustomerID] FROM Sales.Customer
			WHERE PersonID IN (SELECT BusinessEntityID FROM Person.Person
                                          WHERE lastname LIKE N'I%' AND PersonType='SC'))

Pueden obtenerse los mismos resultados si lo cambia a INNER JOIN, como se muestra a continuación:

SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.lastname LIKE N'I%'

Otra forma de reescribirlo es usando una tabla derivada como fuente de tabla para INNER JOIN:

SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN (SELECT c.CustomerID, P.PersonType, P.LastName
            FROM Sales.Customer c
            INNER JOIN Person.Person p ON c.PersonID = P.BusinessEntityID
	      WHERE p.PersonType = 'SC'
	        AND p.LastName LIKE N'I%') AS q ON o.CustomerID = q.CustomerID

Las 3 consultas generan los mismos 48 registros.

9. Uso de sugerencias para unirse

La siguiente consulta utiliza un bucle anidado:

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

Si desea forzarlo a una combinación Hash, esto es lo que sucede:

SELECT
 sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER HASH JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);

Sin embargo, tenga en cuenta que STATISTICS IO muestra que el rendimiento empeorará cuando lo fuerce a una combinación Hash.

Mientras tanto, la consulta a continuación utiliza una combinación de combinación:

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

Esto es en lo que se convierte cuando lo fuerza a un bucle anidado:

SELECT
 soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER LOOP JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID

Al verificar el IO de ESTADÍSTICAS de ambos, forzarlo a un bucle anidado requiere más recursos para procesar la consulta:

Por lo tanto, el uso de sugerencias de unión debería ser su último recurso cuando ajuste el rendimiento. Deje que su SQL Server lo maneje por usted.

10. Usando INNER JOIN en ACTUALIZAR

También puede usar INNER JOIN en una instrucción UPDATE. He aquí un ejemplo:

UPDATE Sales.SalesOrderHeader
SET ShipDate = getdate() 
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'

Ya que es posible usar una unión en una ACTUALIZACIÓN, ¿por qué no probarlo usando ELIMINAR e INSERTAR?

Conclusiones de SQL Join e INNER JOIN

Entonces, ¿cuál es el problema de la unión SQL?

  • Un SQL JOIN combina registros de 2 o más tablas para formar un conjunto de resultados.
  • Hay tipos de uniones en SQL:INNER, OUTER y CROSS.
  • Como desarrollador o administrador, usted decide qué operaciones lógicas o tipos de combinación usar para sus requisitos.
  • Por otro lado, el Optimizador de consultas decide cuáles son los mejores operadores de unión física que se deben usar. Puede ser bucle anidado, combinación, hash o adaptativo.
  • Puede usar sugerencias de unión para forzar qué unión física usar, pero debería ser su último recurso. En la mayoría de los casos, es mejor dejar que SQL Server lo maneje.
  • Conocer los operadores de combinación física también lo ayuda a ajustar el rendimiento de las consultas.
  • Además, las subconsultas se pueden reescribir mediante combinaciones.

Mientras tanto, esta publicación mostró 10 ejemplos de INNER JOIN. No son solo códigos de muestra. Algunos de ellos también incluyen una inspección de cómo funciona el código de adentro hacia afuera. No es solo para ayudarlo a codificar, sino para ayudarlo a tener en cuenta el rendimiento. Al final del día, los resultados no solo deben ser correctos sino también entregados rápidamente.

Aún no hemos terminado. El siguiente artículo se ocupará de OUTER JOINS. Estén atentos.

Véase también

SQL Joins le permite obtener y combinar datos de más de una tabla. Mire este video para obtener más información sobre SQL Joins.