Database
 sql >> Base de données >  >> RDS >> Database

Votre guide ultime de la jointure SQL :INNER JOIN – Partie 1

Jointure interne, jointure externe, jointure croisée ? Qu'est-ce que ça donne ?

C'est une question valable. J'ai vu une fois un code Visual Basic avec des codes T-SQL intégrés. Le code VB récupère les enregistrements de table avec plusieurs instructions SELECT, un SELECT * par table. Ensuite, il combine plusieurs ensembles de résultats dans un ensemble d'enregistrements. Absurde ?

Pour les jeunes développeurs qui l'ont fait, ce n'était pas le cas. Mais lorsqu'ils m'ont demandé d'évaluer pourquoi le système était lent, ce problème a été le premier à attirer mon attention. C'est exact. Ils n'ont jamais entendu parler des jointures SQL. En toute honnêteté envers eux, ils étaient honnêtes et ouverts aux suggestions.

Comment décrivez-vous les jointures SQL ? Peut-être vous souvenez-vous d'une chanson - Imagine par John Lennon :

Vous pouvez dire que je suis un rêveur, mais je ne suis pas le seul.

J'espère qu'un jour vous nous rejoindrez et que le monde ne fera plus qu'un.

Dans le contexte de la chanson, rejoindre c'est unir. Dans une base de données SQL, la combinaison d'enregistrements de 2 tables ou plus dans un ensemble de résultats forme une jointure .

Cet article est le début d'une série en 3 parties sur les jointures SQL :

  • JOINTURE INTERNE
  • OUTER JOIN, qui inclut LEFT, RIGHT et FULL
  • JOINTURE CROISÉE

Mais avant de commencer à parler de INNER JOIN, décrivons les jointures en général.

En savoir plus sur SQL JOIN

Les jointures apparaissent juste après la clause FROM. Dans sa forme la plus simple, cela ressemble à la norme 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>]

Décrivons les choses quotidiennes entourant le JOIN.

Sources du tableau

Vous pouvez ajouter jusqu'à 256 sources de tables, selon Microsoft. Bien sûr, cela dépend des ressources de votre serveur. Je n'ai jamais rejoint plus de 10 tables dans ma vie, sans parler de 256. Quoi qu'il en soit, les sources de table peuvent être l'une des suivantes :

  • Tableau
  • Afficher
  • Synonyme de tableau ou de vue
  • Variable de tableau
  • Fonction table
  • Table dérivée

Alias ​​de table

Un alias est facultatif, mais il raccourcit votre code et minimise la saisie. Cela vous aide également à éviter les erreurs lorsqu'un nom de colonne existe dans deux ou plusieurs tables utilisées dans un SELECT, UPDATE, INSERT ou DELETE. Cela ajoute également de la clarté à votre code. C'est facultatif, mais je vous recommande d'utiliser des alias. (Sauf si vous aimez taper les sources de table par leur nom.)

Condition de jointure

Le mot-clé ON précède la condition de jointure qui peut être une seule jointure ou des colonnes à 2 clés des 2 tables jointes. Ou il peut s'agir d'une jointure composite utilisant plus de 2 colonnes clés. Il définit la manière dont les tables sont liées.

Cependant, nous utilisons la condition de jointure uniquement pour les jointures INNER et OUTER. L'utiliser sur un CROSS JOIN déclenchera une erreur.

Puisque les conditions de jointure définissent les relations, elles ont besoin d'opérateurs.

L'opérateur de condition de jointure le plus courant est l'opérateur d'égalité (=). D'autres opérateurs comme> ou

SQL JOIN vs sous-requêtes

La plupart des jointures peuvent être réécrites sous forme de sous-requêtes et vice-versa. Consultez cet article pour en savoir plus sur les sous-requêtes par rapport aux jointures.

Joints et tables dérivées

L'utilisation de tables dérivées dans une jointure ressemble à ceci :

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

Il se joint à partir du résultat d'une autre instruction SELECT, et il est parfaitement valide.

Vous aurez plus d'exemples, mais parlons d'une dernière chose à propos de SQL JOINS. C'est ainsi que les processus de l'optimiseur de requêtes de SQL Server se joignent.

Comment SQL Server traite les jointures

Pour comprendre le fonctionnement du processus, vous devez connaître les deux types d'opérations impliquées :

  • Opérations logiques correspondent aux types de jointures utilisés dans une requête :INNER, OUTER ou CROSS. En tant que développeur, vous définissez cette partie du traitement lors de la formation de la requête.
  • Opérations physiques – l'optimiseur de requête choisit la meilleure opération physique applicable pour votre jointure. Le meilleur signifie le plus rapide pour produire des résultats. Le plan d'exécution de votre requête affichera les opérateurs de jointure physique choisis. Ces opérations sont :
    • Jointure en boucle imbriquée. Cette opération est rapide si l'une des deux tables est petite et la seconde grande et indexée. Il nécessite le moins d'E/S avec le moins de comparaisons, mais ce n'est pas bon pour les grands ensembles de résultats.
    • Fusionner la jointure. Il s'agit de l'opération la plus rapide pour les ensembles de résultats volumineux et triés par colonnes utilisées dans la jointure.
    • Hash Join. L'optimiseur de requête l'utilise lorsque le jeu de résultats est trop volumineux pour une boucle imbriquée et que les entrées ne sont pas triées pour une jointure de fusion. Un hachage est plus efficace que de le trier d'abord et d'appliquer une jointure par fusion.
    • Joindre adaptative. À partir de SQL Server 2017, il permet le choix entre une boucle imbriquée ou un hachage . La méthode de jointure est différée jusqu'à ce que la première entrée soit analysée. Cette opération bascule dynamiquement vers une meilleure jointure physique sans recompilation.

Pourquoi devons-nous nous embêter avec ça ?

Un seul mot :performances.

Une chose est de savoir comment former des requêtes avec des jointures pour produire des résultats corrects. Une autre consiste à le faire fonctionner aussi vite que possible. Vous devez vous préoccuper davantage de cela si vous voulez une bonne réputation auprès de vos utilisateurs.

Alors, que devez-vous rechercher dans le plan d'exécution pour ces opérations logiques ?

  • Supposons qu'un opérateur de tri précède la jointure de fusion . Cette opération de tri est coûteuse pour les grandes tables (Figure 2). Vous pouvez résoudre ce problème en pré-triant les tables d'entrée dans la jointure.
  • Supposons qu'il existe des doublons dans les tables d'entrée d'une jointure de fusion . SQL Server écrira les doublons de la deuxième table dans une WorkTable dans tempdb. Ensuite, il y fera les comparaisons. L'OI STATISTIQUES révélera toutes les tables de travail impliquées.
  • Lorsque d'énormes données sont déversées sur tempdb dans un Hash jo dans, le STATISTICS IO révélera une grande lecture logique sur WorkFiles ou WorkTables. Un avertissement apparaîtra également dans le plan d'exécution (Figure 3). Vous pouvez appliquer deux choses :pré-trier les tables d'entrée ou réduire les jointures, si possible. Par conséquent, l'optimiseur de requête peut choisir une autre jointure physique.

Conseils d'adhésion

Les indicateurs de jointure sont nouveaux dans SQL Server 2019. Lorsque vous les utilisez dans vos jointures, ils indiquent à l'optimiseur de requête d'arrêter de décider ce qui convient le mieux à la requête. Vous êtes le patron quand il s'agit de la jointure physique à utiliser.

Maintenant, arrêtez-vous, juste là. En réalité, l'optimiseur de requête sélectionne généralement la meilleure jointure physique pour votre requête. Si vous ne savez pas ce que vous faites, n'utilisez pas d'indicateurs de jointure.

Les conseils possibles que vous pouvez spécifier sont LOOP, MERGE, HASH ou REMOTE.

Je n'ai pas utilisé d'indicateurs de jointure, mais voici la syntaxe :


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

Tout sur la jointure interne

INNER JOIN renvoie les lignes avec des enregistrements correspondants dans les deux tables, en fonction d'une condition. C'est aussi la jointure par défaut si vous ne spécifiez pas le mot-clé INNER :

Comme vous le voyez, les lignes correspondantes de Table1 et Table2 sont renvoyés à l'aide de Key1 comme condition de jointure. Le Table1 enregistrement ayant Key1 ='C' est exclu car il n'y a pas d'enregistrements correspondants dans Table2 .

Chaque fois que je forme une requête, mon premier choix est INNER JOIN. OUTER JOIN n'intervient que lorsque les exigences l'imposent.

Syntaxe INNER JOIN

Il existe deux syntaxes INNER JOIN prises en charge dans T-SQL :SQL-92 et SQL-89.

JOINTURE INTERNE SQL-92

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>]

JOINTURE INTERNE SQL-89

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>)]

Quelle syntaxe INNER JOIN est la meilleure ?

La première syntaxe de jointure que j'ai apprise était SQL-89. Lorsque SQL-92 est finalement arrivé, j'ai pensé que c'était trop long. J'ai aussi pensé que le résultat était le même, pourquoi s'embêter à taper plus de mots-clés ? Un concepteur de requêtes graphique avait le code généré SQL-92, et je l'ai changé en SQL-89. Mais aujourd'hui, je préfère SQL-92 même si je dois taper plus. Voici pourquoi :

  • L'intention du type de jointure est claire. Le prochain gars ou fille qui maintiendra mon code saura ce qui est prévu dans la requête.
  • Oublier la condition de jointure dans une syntaxe SQL-92 déclenchera une erreur. Pendant ce temps, l'oubli de la condition de jointure dans SQL-89 sera traité comme un CROSS JOIN. Si je voulais dire une jointure INNER ou OUTER, ce serait un bogue logique imperceptible jusqu'à ce que les utilisateurs se plaignent.
  • Les nouveaux outils sont plus enclins à SQL-92. Si jamais j'utilise à nouveau un concepteur de requêtes graphique, je n'ai pas à le changer en SQL-89. Je ne suis plus têtu, donc mon rythme cardiaque est revenu à la normale. Bravo à moi.

Les raisons ci-dessus sont les miennes. Vous pouvez avoir vos raisons pour lesquelles vous préférez SQL-92 ou pourquoi vous le détestez. Je me demande quelles sont ces raisons. Faites-le moi savoir dans la section Commentaires ci-dessous.

Mais nous ne pouvons pas terminer cet article sans exemples et explications.

10 exemples de jointures internes

1. Joindre 2 tables

Voici un exemple de 2 tables jointes à l'aide de INNER JOIN dans la syntaxe 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

Vous ne spécifiez que les colonnes dont vous avez besoin. Dans l'exemple ci-dessus, 4 colonnes sont spécifiées. Je sais que c'est trop long que SELECT * mais gardez ceci à l'esprit :c'est la meilleure pratique.

Notez également l'utilisation d'alias de table. Le Produit et ProductSubcategory les tables ont une colonne nommée [Nom ]. Si vous ne spécifiez pas l'alias, une erreur sera déclenchée.

En attendant, voici la syntaxe SQL-89 équivalente :

-- 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);

Ils sont identiques à l'exception de la condition de jointure mélangée dans la clause WHERE avec un mot-clé AND. Mais sous le capot, sont-ils vraiment les mêmes ? Examinons le jeu de résultats, les E/S STATISTIQUES et le plan d'exécution.

Voir le jeu de résultats de 9 enregistrements :

Ce ne sont pas seulement les résultats, mais les ressources requises par SQL Server sont également les mêmes.

Voir les lectures logiques :

Enfin, le plan d'exécution révèle le même plan de requête pour les deux requêtes lorsque leur QueryPlanHashes sont égaux. Remarquez également les opérations en surbrillance dans le diagramme :

Sur la base des résultats, le traitement des requêtes SQL Server est le même, qu'il s'agisse de SQL-92 ou de SQL-89. Mais comme je l'ai dit, la clarté dans SQL-92 est bien meilleure pour moi.

La figure 7 montre également une jointure de boucle imbriquée utilisée dans le plan. Pourquoi? L'ensemble de résultats est petit.

2. Rejoindre plusieurs tables

Découvrez la requête ci-dessous en utilisant 3 tables jointes.

-- 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. Jointure composite

Vous pouvez également joindre 2 tableaux en utilisant 2 clés pour le relier. Découvrez l'exemple ci-dessous. Il utilise 2 conditions de jointure avec un opérateur 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 Utilisation d'une jointure physique de boucle imbriquée

Dans l'exemple ci-dessous, le Produit table a 9 enregistrements - un petit ensemble. La table jointe est SalesOrderDetail – un grand ensemble. L'optimiseur de requête utilisera une jointure de boucle imbriquée, comme illustré à la figure 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 Utilisation d'une jointure physique de fusion

L'exemple ci-dessous utilise une jointure par fusion car les deux tables d'entrée sont triées par 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 Utilisation d'une jointure physique par hachage

L'exemple suivant utilisera une jointure par hachage :

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 Utilisation de la jointure physique adaptative

Dans l'exemple ci-dessous, le Vendeur la table a un index ColumnStore non clusterisé sur TerritoryID colonne. L'optimiseur de requête a opté pour une jointure de boucle imbriquée, comme illustré à la figure 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. Deux façons de réécrire une sous-requête en INNER JOIN

Considérez cette déclaration avec une sous-requête imbriquée :

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'))

Les mêmes résultats peuvent apparaître si vous le remplacez par INNER JOIN, comme ci-dessous :

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%'

Une autre façon de le réécrire consiste à utiliser une table dérivée comme source de table pour 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

Les 3 requêtes génèrent les mêmes 48 enregistrements.

9. Utilisation des conseils de jointure

La requête suivante utilise une boucle imbriquée :

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 vous voulez le forcer à une jointure par hachage, voici ce qui se passe :

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);

Cependant, notez que STATISTICS IO montre que les performances se dégradent lorsque vous le forcez à une jointure par hachage.

Pendant ce temps, la requête ci-dessous utilise une jointure par fusion :

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

Voici ce qu'il devient lorsque vous le forcez sur une boucle imbriquée :

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

Lors de la vérification des STATISTICS IO des deux, le forcer à une boucle imbriquée nécessite plus de ressources pour traiter la requête :

Ainsi, l'utilisation d'indicateurs de jointure devrait être votre dernier recours lorsque vous peaufinez les performances. Laissez votre serveur SQL le gérer pour vous.

10. Utiliser INNER JOIN dans UPDATE

Vous pouvez également utiliser INNER JOIN dans une instruction UPDATE. Voici un exemple :

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'

Puisqu'il est possible d'utiliser une jointure dans un UPDATE, pourquoi ne pas essayer en utilisant DELETE et INSERT ?

Partage SQL Join et INNER JOIN

Alors, quel est le problème avec la jointure SQL ?

  • Une jointure SQL combine les enregistrements de 2 tables ou plus pour former un ensemble de résultats.
  • Il existe plusieurs types de jointures en SQL :INNER, OUTER et CROSS.
  • En tant que développeur ou administrateur, vous décidez des opérations logiques ou des types de jointure à utiliser selon vos besoins.
  • D'autre part, l'optimiseur de requête décide des meilleurs opérateurs de jointure physique à utiliser. Il peut s'agir d'une boucle imbriquée, d'une fusion, d'un hachage ou d'une adaptation.
  • Vous pouvez utiliser des indications de jointure pour forcer la jointure physique à utiliser, mais cela devrait être votre dernier recours. Dans la plupart des cas, il est préférable de laisser votre serveur SQL s'en charger.
  • La connaissance des opérateurs de jointure physique vous aide également à optimiser les performances des requêtes.
  • De plus, les sous-requêtes peuvent être réécrites à l'aide de jointures.

Pendant ce temps, ce post a montré 10 exemples de INNER JOINs. Ce ne sont pas seulement des exemples de codes. Certains d'entre eux incluent également une inspection du fonctionnement du code de l'intérieur. Ce n'est pas seulement pour vous aider à coder, mais pour vous aider à être attentif aux performances. En fin de compte, les résultats ne doivent pas seulement être corrects, mais également livrés rapidement.

Nous n'avons pas encore fini. Le prochain article traitera des JOINS EXTERNES. Restez à l'écoute.

Voir aussi

Les jointures SQL vous permettent d'extraire et de combiner des données de plusieurs tables. Regardez cette vidéo pour en savoir plus sur les jointures SQL.