Database
 sql >> Database >  >> RDS >> Database

La tua guida definitiva all'unione con SQL:INNER JOIN – Parte 1

Join interno, join esterno, join incrociato? Cosa dà?

È una domanda valida. Una volta ho visto un codice Visual Basic con codici T-SQL incorporati. Il codice VB recupera i record della tabella con più istruzioni SELECT, una SELECT * per tabella. Quindi, combina più set di risultati in un set di record. Assurdo?

Per i giovani sviluppatori che l'hanno fatto, non lo era. Ma quando mi hanno chiesto di valutare il motivo per cui il sistema era lento, quel problema è stato il primo ad attirare la mia attenzione. Giusto. Non hanno mai sentito parlare di join SQL. In tutta onestà, sono stati onesti e aperti ai suggerimenti.

Come descrivi i join SQL? Forse ti ricordi una canzone:Imagine di John Lennon:

Puoi dire che sono un sognatore, ma non sono l'unico.

Spero che un giorno ti unirai a noi e il mondo sarà come uno.

Nel contesto della canzone, unirsi è unire. In un database SQL, la combinazione di record di 2 o più tabelle in un set di risultati forma un join .

Questo articolo è l'inizio di una serie in 3 parti che parla di join SQL:

  • UNIONE INTERNA
  • OUTER JOIN, che include SINISTRA, DESTRA e COMPLETA
  • CROSS UNISCITI

Ma prima di iniziare a discutere di INNER JOIN, descriviamo i join in generale.

Ulteriori informazioni su SQL JOIN

I join vengono visualizzati subito dopo la clausola FROM. Nella sua forma più semplice, sembra usare lo standard 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>]

Descriviamo le cose quotidiane che circondano il JOIN.

Fonti tabella

È possibile aggiungere fino a 256 origini tabelle, secondo Microsoft. Naturalmente, dipende dalle risorse del tuo server. Non ho mai aderito a più di 10 tavoli in vita mia, per non parlare di 256. Ad ogni modo, le fonti delle tabelle possono essere una delle seguenti:

  • Tabella
  • Visualizza
  • Tabella o visualizza sinonimo
  • Variabile tabella
  • Funzione con valori di tabella
  • Tabella derivata

Alias ​​tabella

Un alias è facoltativo, ma accorcia il codice e riduce al minimo la digitazione. Consente inoltre di evitare errori quando esiste un nome di colonna in due o più tabelle utilizzate in SELECT, UPDATE, INSERT o DELETE. Aggiunge anche chiarezza al tuo codice. È facoltativo, ma consiglierei di utilizzare gli alias. (A meno che non ti piaccia digitare le origini delle tabelle per nome.)

Condizione di adesione

La parola chiave ON precede la condizione di join che può essere un join singolo o colonne a 2 chiavi delle 2 tabelle unite. Oppure può essere un join composito che utilizza più di 2 colonne chiave. Definisce come sono correlate le tabelle.

Tuttavia, utilizziamo la condizione di unione solo per i join INNER e OUTER. Il suo utilizzo su un CROSS JOIN attiverà un errore.

Poiché le condizioni di unione definiscono le relazioni, hanno bisogno di operatori.

Il più comune degli operatori di condizioni di join è l'operatore di uguaglianza (=). Anche altri operatori come> o

SQL JOIN e sottoquery

La maggior parte dei join può essere riscritta come subquery e viceversa. Consulta questo articolo per ulteriori informazioni sulle sottoquery rispetto ai join.

Join e tabelle derivate

L'utilizzo di tabelle derivate in un join è simile al seguente:

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

Si unisce dal risultato di un'altra istruzione SELECT ed è perfettamente valido.

Avrai più esempi, ma affrontiamo un'ultima cosa su SQL JOINS. È il modo in cui Query Optimizer di SQL Server elabora i join.

Come SQL Server elabora i join

Per capire come funziona il processo, devi conoscere i due tipi di operazioni coinvolte:

  • Operazioni logiche corrispondono ai tipi di join utilizzati in una query:INNER, OUTER o CROSS. Tu, come sviluppatore, definisci questa parte dell'elaborazione durante la creazione della query.
  • Operazioni fisiche – Query Optimizer sceglie la migliore operazione fisica applicabile per il tuo join. Il migliore significa il più veloce per produrre risultati. Il Piano di esecuzione della tua query mostrerà gli operatori di join fisici scelti. Queste operazioni sono:
    • Unisciti al loop nidificato. Questa operazione è veloce se una delle due tabelle è piccola e la seconda è grande e indicizzata. Richiede il minimo I/O con il minor numero di confronti, ma non va bene per set di risultati di grandi dimensioni.
    • Unisci Unisciti. Questa è l'operazione più veloce per set di risultati di grandi dimensioni e ordinati per colonne utilizzate nel join.
    • Unisciti con hash. Query Optimizer lo usa quando il set di risultati è troppo grande per un ciclo nidificato e gli input non sono ordinati per un merge join. Un hash è più efficiente che ordinarlo prima e applicare un join Merge.
    • Partecipa adattiva. A partire da SQL Server 2017, consente la scelta tra un ciclo nidificato o un hash . Il metodo di unione viene posticipato fino alla scansione del primo input. Questa operazione passa in modo dinamico a un join fisico migliore senza ricompilare.

Perché dobbiamo preoccuparci di questo?

Una parola:prestazioni.

Una cosa è sapere come formare query con i join per produrre risultati corretti. Un altro è farlo funzionare il più velocemente possibile. Devi essere molto preoccupato per questo se vuoi una buona reputazione con i tuoi utenti.

Quindi, a cosa devi prestare attenzione nel Piano di esecuzione per queste operazioni logiche?

  • Supponiamo che un operatore di ordinamento preceda l'unione unisci . Questa operazione di ordinamento è costosa per le tabelle di grandi dimensioni (Figura 2). Puoi risolvere questo problema preordinando le tabelle di input nel join.
  • Supponiamo che ci siano duplicati nelle tabelle di input di un Merge join . SQL Server scriverà i duplicati della seconda tabella in una tabella di lavoro in tempdb. Quindi, farà i confronti lì. L'IO di STATISTICHE rivelerà tutte le tabelle di lavoro coinvolte.
  • Quando enormi dati si riversano su tempdb in un hash jo in, STATISTICS IO rivelerà un'ampia lettura logica su WorkFiles o WorkTables. Verrà visualizzato anche un avviso nel Piano di esecuzione (Figura 3). Puoi applicare due cose:preordinare le tabelle di input o ridurre i join, se possibile. Di conseguenza, Query Optimizer può scegliere un altro join fisico.

Suggerisci unisciti

I suggerimenti per il join sono una novità in SQL Server 2019. Quando lo usi nei tuoi join, indica a Query Optimizer di interrompere la decisione di cosa è meglio per la query. Sei il capo quando si tratta del join fisico da utilizzare.

Ora fermati, proprio lì. La verità è che Query Optimizer in genere seleziona il miglior join fisico per la tua query. Se non sai cosa stai facendo, non utilizzare i suggerimenti di partecipazione.

I possibili suggerimenti che puoi specificare sono LOOP, MERGE, HASH o REMOTE.

Non ho usato i suggerimenti di partecipazione, ma ecco la sintassi:


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

Tutto su INNER JOIN

INNER JOIN restituisce le righe con i record corrispondenti in entrambe le tabelle, in base a una condizione. È anche il join predefinito se non specifichi la parola chiave INNER:

Come puoi vedere, righe corrispondenti da Tabella1 e Tabella2 vengono restituiti utilizzando Key1 come condizione di unione. La Tabella1 record con Chiave1 ='C' è esclusa perché non ci sono record corrispondenti nella Tabella2 .

Ogni volta che formulo una query, la mia prima scelta è INNER JOIN. OUTER JOIN arriva solo quando i requisiti lo richiedono.

Sintassi INNER JOIN

Esistono due sintassi INNER JOIN supportate in T-SQL:SQL-92 e SQL-89.

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

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

Quale sintassi INNER JOIN è migliore?

La prima sintassi di join che ho imparato è stata SQL-89. Quando finalmente è arrivato SQL-92, ho pensato che fosse troppo lungo. Ho anche pensato che l'output fosse lo stesso, perché preoccuparsi di digitare più parole chiave? Un progettista grafico di query aveva il codice generato SQL-92 e l'ho cambiato di nuovo in SQL-89. Ma oggi preferisco SQL-92 anche se devo digitare di più. Ecco perché:

  • L'intenzione del tipo di unione è chiara. Il prossimo ragazzo o ragazza che manterrà il mio codice saprà cosa si intende nella query.
  • Dimenticare la condizione di join in una sintassi SQL-92 attiverà un errore. Nel frattempo, dimenticare la condizione di join in SQL-89 verrà trattato come un CROSS JOIN. Se intendessi un join INNER o OUTER, sarebbe un bug logico impercettibile fino a quando gli utenti non si lamentano.
  • I nuovi strumenti sono più inclini a SQL-92. Se dovessi utilizzare nuovamente un progettista di query grafiche, non devo cambiarlo in SQL-89. Non sono più testardo, quindi la mia frequenza cardiaca è tornata alla normalità. Auguri a me.

I motivi di cui sopra sono miei. Potresti avere le tue ragioni per cui preferisci SQL-92 o perché lo odi. Mi chiedo quali siano queste ragioni. Fammi sapere nella sezione Commenti qui sotto.

Ma non possiamo concludere questo articolo senza esempi e spiegazioni.

10 Esempi di INNER JOIN

1. Unire 2 Tabelle

Ecco un esempio di 2 tabelle unite insieme utilizzando INNER JOIN nella sintassi 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

Specifica solo le colonne di cui hai bisogno. Nell'esempio sopra, sono specificate 4 colonne. So che è troppo lungo di SELECT * ma tienilo a mente:è la migliore pratica.

Notare anche l'uso di alias di tabella. Sia il Prodotto e Sottocategoria di prodotto le tabelle hanno una colonna denominata [Nome ]. Se non specifichi l'alias, verrà generato un errore.

Nel frattempo, ecco la sintassi 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);

Sono gli stessi tranne che per la condizione di join mista nella clausola WHERE con una parola chiave AND. Ma sotto il cofano, sono davvero la stessa cosa? Esaminiamo il set di risultati, STATISTICS IO e il Piano di esecuzione.

Vedi il set di risultati di 9 record:

Non sono solo i risultati, ma anche le risorse richieste da SQL Server sono le stesse.

Vedi le letture logiche:

Infine, il piano di esecuzione rivela lo stesso piano di query per entrambe le query quando i loro QueryPlanHashes sono uguali. Notare anche le operazioni evidenziate nel diagramma:

Sulla base dei risultati, l'elaborazione delle query di SQL Server è la stessa, indipendentemente dal fatto che si tratti di SQL-92 o SQL-89. Ma come ho detto, la chiarezza in SQL-92 è molto migliore per me.

La figura 7 mostra anche un Nested Loop Join utilizzato nel piano. Come mai? Il set di risultati è piccolo.

2. Unire più tabelle

Controlla la query di seguito utilizzando 3 tabelle unite.

-- 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. Partecipazione composita

Puoi anche unire 2 tavoli usando 2 chiavi per metterlo in relazione. Dai un'occhiata all'esempio qui sotto. Utilizza 2 condizioni di unione con un operatore 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 Utilizzo di un collegamento fisico a loop nidificato

Nell'esempio seguente, il Prodotto la tabella ha 9 record:un piccolo set. La tabella unita è SalesOrderDetail – un grande set. Query Optimizer utilizzerà un Nested Loop Join, come mostrato nella 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 Utilizzo di un join fisico di unione

L'esempio seguente utilizza un Merge Join perché entrambe le tabelle di input sono ordinate per 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 Utilizzo di un join fisico hash

L'esempio seguente utilizzerà 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 Utilizzo di Adaptive Physical Join

Nell'esempio seguente, il Addetto alle vendite la tabella ha un indice ColumnStore non cluster su TerritoryID colonna. Query Optimizer ha deciso un join del ciclo nidificato, come mostrato nella 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. Due modi per riscrivere una sottoquery in un INNER JOIN

Considera questa affermazione con una sottoquery nidificata:

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

Gli stessi risultati possono venire fuori se lo modifichi in un INNER JOIN, come di seguito:

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

Un altro modo per riscriverlo è utilizzare una tabella derivata come origine tabella per 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

Tutte e 3 le query generano gli stessi 48 record.

9. Utilizzo dei suggerimenti per l'adesione

La query seguente utilizza un ciclo annidato:

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

Se vuoi forzarlo a un hash join, ecco cosa succede:

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

Tuttavia, tieni presente che STATISTICS IO mostra che le prestazioni peggiorano quando lo forzi a un hash join.

Nel frattempo, la query seguente utilizza un Merge Join:

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

Ecco cosa diventa quando lo forzi a un ciclo nidificato:

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

Dopo aver verificato l'IO di STATISTICHE di entrambi, forzarlo a un ciclo nidificato richiede più risorse per elaborare la query:

Pertanto, l'utilizzo dei suggerimenti di unione dovrebbe essere l'ultima risorsa quando si ottimizzano le prestazioni. Lascia che sia il tuo SQL Server a gestirlo per te.

10. Utilizzo di INNER JOIN in UPDATE

Puoi anche utilizzare INNER JOIN in un'istruzione UPDATE. Ecco un esempio:

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'

Poiché è possibile utilizzare un join in un AGGIORNAMENTO, perché non provarlo utilizzando DELETE e INSERT?

Asporto SQL Join e INNER JOIN

Allora, qual è il problema di SQL join?

  • Un SQL JOIN combina record di 2 o più tabelle per formare un set di risultati.
  • Ci sono tipi di join in SQL:INNER, OUTER e CROSS.
  • In qualità di sviluppatore o amministratore, sei tu a decidere quali operazioni logiche o tipi di join utilizzare per le tue esigenze.
  • D'altra parte, Query Optimizer decide i migliori operatori di join fisici da utilizzare. Può essere Nested Loop, Merge, Hash o Adaptive.
  • Puoi usare i suggerimenti di unione per forzare quale unione fisica usare, ma dovrebbe essere la tua ultima risorsa. Nella maggior parte dei casi, è meglio lasciare che sia il tuo SQL Server a gestirlo.
  • Conoscere gli operatori di join fisici ti aiuta anche a ottimizzare le prestazioni delle query.
  • Inoltre, le sottoquery possono essere riscritte usando i join.

Nel frattempo, questo post ha mostrato 10 esempi di INNER JOIN. Non sono solo codici di esempio. Alcuni di essi includono anche un'ispezione di come funziona il codice dall'interno verso l'esterno. Non è solo per aiutarti a programmare, ma per aiutarti a essere consapevole delle prestazioni. Alla fine della giornata, i risultati non dovrebbero essere solo corretti ma anche consegnati rapidamente.

Non abbiamo ancora finito. Il prossimo articolo tratterà delle OUTER JOINS. Resta sintonizzato.

Vedi anche

I join SQL consentono di recuperare e combinare dati da più tabelle. Guarda questo video per saperne di più sui join SQL.