sql >> Databasteknik >  >> RDS >> Database

Din ultimata guide till SQL Join:INNER JOIN – Del 1

Inre sammanfogning, yttre sammanfogning, tvärfogning? Vad ger?

Det är en giltig fråga. Jag såg en gång en Visual Basic-kod med T-SQL-koder inbäddade i den. VB-koden hämtar tabellposter med flera SELECT-satser, en SELECT* per tabell. Sedan kombinerar den flera resultatuppsättningar till en rekorduppsättning. Absurt?

För de unga utvecklarna som gjorde det var det inte det. Men när de bad mig att utvärdera varför systemet var långsamt, var det problemet det första som fångade min uppmärksamhet. Det är rätt. De har aldrig hört talas om SQL-anslutningar. I rättvisans namn var de ärliga och öppna för förslag.

Hur beskriver du SQL-anslutningar? Kanske kommer du ihåg en låt – Imagine av John Lennon:

Du kan säga att jag är en drömmare, men jag är inte den enda.

Jag hoppas att du en dag kommer att ansluta sig till oss, och att världen kommer att vara som en.

I låtens sammanhang är sammanfogning att förena. I en SQL-databas, att kombinera poster med 2 eller flera tabeller till en resultatuppsättning bildar en sammanfogning .

Den här artikeln är början på en serie i tre delar som talar om SQL-anslutningar:

  • INRE JOIN
  • OUTTER JOIN, som inkluderar LEFT, RIGHT och FULL
  • KORS-GÅ MED

Men innan vi börjar diskutera INNER JOIN, låt oss beskriva anslutningar i allmänhet.

Mer om SQL JOIN

Joins visas direkt efter FROM-satsen. I sin enklaste form ser det ut som att använda SQL-92-standarden:

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

Låt oss beskriva de vardagliga sakerna kring JOIN.

Tabellkällor

Du kan lägga till upp till 256 tabellkällor, enligt Microsoft. Naturligtvis beror det på dina serverresurser. Jag har aldrig gått med i mer än 10 bord i mitt liv, för att inte tala om 256. Hur som helst, tabellkällor kan vara något av följande:

  • Tabell
  • Visa
  • Synonym för tabell eller vy
  • Tabellvariabel
  • Tabellvärderad funktion
  • Härledd tabell

Tabellalias

Ett alias är valfritt, men det förkortar din kod och minimerar skrivning. Det hjälper dig också att undvika fel när ett kolumnnamn finns i två eller flera tabeller som används i en SELECT, UPDATE, INSERT eller DELETE. Det ger också klarhet till din kod. Det är valfritt, men jag rekommenderar att du använder alias. (Om du inte älskar att skriva tabellkällor efter namn.)

Anslutningsvillkor

Nyckelordet ON föregår kopplingsvillkoret som kan vara en enkel koppling eller kolumner med 2 nyckel från de 2 sammanfogade tabellerna. Eller det kan vara en sammansatt koppling med fler än 2 nyckelkolumner. Den definierar hur tabeller är relaterade.

Däremot använder vi sammanfogningsvillkoret endast för INNER och OUTER sammanfogningar. Att använda det på en CROSS JOIN kommer att utlösa ett fel.

Eftersom anslutningsvillkoren definierar relationerna behöver de operatörer.

Den vanligaste operatorn för joinvillkor är likhetsoperator (=). Andra operatörer som> eller

SQL JOIN vs. Subqueries

De flesta anslutningar kan skrivas om som delfrågor och vice versa. Kolla in den här artikeln för att lära dig mer om delfrågor jämfört med anslutningar.

Joins och härledda tabeller

Att använda härledda tabeller i en join ser ut så här:

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

Det går med från resultatet av en annan SELECT-sats, och den är helt giltig.

Du kommer att ha fler exempel, men låt oss ta itu med en sista sak om SQL JOINS. Det är hur SQL Servers Query Optimizer-processer ansluts.

Hur SQL Server Processer ansluter

För att förstå hur processen fungerar måste du känna till de två typerna av operationer som är involverade:

  • Logiska operationer motsvarar de jointyper som används i en fråga:INNER, OUTER eller CROSS. Du, som utvecklare, definierar denna del av bearbetningen när du skapar frågan.
  • Fysisk operation – Query Optimizer väljer den bästa fysiska operationen för din anslutning. Det bästa betyder att det snabbast ger resultat. Exekutionsplanen för din fråga kommer att visa de valda fysiska anslutningsoperatörerna. Dessa operationer är:
    • Nested Loop Join. Denna operation är snabb om en av de två tabellerna är liten och den andra är stor och indexerad. Det kräver minst I/O med minst jämförelser, men det är inte bra för stora resultatuppsättningar.
    • Slå samman gå med. Detta är den snabbaste operationen för stora och sorterade resultatuppsättningar efter kolumner som används i sammanfogningen.
    • Hash Join. Frågeoptimeraren använder den när resultatuppsättningen är för stor för en kapslad loop och indata är osorterade för en sammanfogning. En hash är effektivare än att sortera den först och använda en sammanfogning.
    • Adaptive Join. Från och med SQL Server 2017 möjliggör den valet mellan en kapslad loop eller hash . Sammanfogningsmetoden skjuts upp tills den första ingången skannas. Denna operation växlar dynamiskt till en bättre fysisk koppling utan omkompilering.

Varför behöver vi bry oss om detta?

Ett ord:Prestanda.

En sak är att veta hur man skapar frågor med kopplingar för att ge korrekta resultat. En annan är att få den att gå så fort som möjligt. Du måste vara extra mån om detta om du vill ha ett gott rykte hos dina användare.

Så vad behöver du hålla utkik efter i exekveringsplanen för dessa logiska operationer?

  • Anta att en sorteringsoperator föregår sammanfogningen . Denna typ av operation är dyr för stora bord (Figur 2). Du kan fixa detta genom att försortera inmatningstabellerna i join.
  • Anta att det finns dubbletter i inmatningstabellerna för en sammanfogning . SQL Server kommer att skriva dubbletter av den andra tabellen till en arbetstabell i tempdb. Sedan kommer den att göra jämförelser där. STATISTICS IO kommer att avslöja alla inblandade arbetstabeller.
  • När enorma data spills till tempdb i en Hash jo i, kommer STATISTICS IO att avslöja en stor logisk läsning på WorkFiles eller WorkTables. En varning kommer också att visas i utförandeplanen (Figur 3). Du kan tillämpa två saker:försortera inmatningstabellerna eller minska kopplingarna, om möjligt. Som ett resultat kan frågeoptimeraren välja en annan fysisk anslutning.

Gå med tips

Join-tips är nya i SQL Server 2019. När du använder det i dina joins säger det till frågeoptimeraren att sluta bestämma vad som är bäst för frågan. Du är chefen när det kommer till den fysiska anslutningen att använda.

Sluta nu, där. Sanningen är att frågeoptimeraren vanligtvis väljer den bästa fysiska kopplingen för din fråga. Om du inte vet vad du gör, använd inte anslutningstips.

De möjliga tipsen du kan ange är LOOP, MERGE, HASH eller REMOTE.

Jag har inte använt anslutningstips, men här är syntaxen:


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

Allt om INNER JOIN

INNER JOIN returnerar raderna med matchande poster i båda tabellerna, baserat på ett villkor. Det är också standardanslutningen om du inte anger sökordet INNER:

Som du ser, matchande rader från Tabell1 och Tabell2 returneras med Key1 som sammanfogningsvillkor. Tabell1 post med Nyckel1 ='C' exkluderas eftersom det inte finns några matchande poster i Tabell2 .

När jag ställer en fråga är mitt första val INNER JOIN. OUTTER JOIN kommer bara när kraven dikterar det.

INNER JOIN Syntax

Det finns två INNER JOIN-syntaxer som stöds i T-SQL:SQL-92 och SQL-89.

SQL-92 INNER JOIN

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 INNER JOIN

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

Vilken INNER JOIN-syntax är bättre?

Den första joinsyntaxen jag lärde mig var SQL-89. När SQL-92 äntligen kom, tyckte jag att det var för långt. Jag tänkte också eftersom resultatet var detsamma, varför bry sig om att skriva fler sökord? En grafisk frågedesigner hade den genererade koden SQL-92, och jag ändrade tillbaka den till SQL-89. Men idag föredrar jag SQL-92 även om jag måste skriva mer. Här är anledningen:

  • Avsikten med typen av koppling är tydlig. Nästa kille eller tjej som kommer att underhålla min kod kommer att veta vad som är tänkt i frågan.
  • Om du glömmer kopplingsvillkoret i en SQL-92-syntax utlöses ett fel. Under tiden kommer att glömma joinvillkoret i SQL-89 behandlas som en CROSS JOIN. Om jag menade en INNER eller OUTER join, skulle det vara en omärklig logisk bugg tills användarna klagar.
  • Nya verktyg är mer benägna att använda SQL-92. Om jag någonsin använder en grafisk frågedesigner igen, behöver jag inte ändra den till SQL-89. Jag är inte längre envis, så min puls är tillbaka till det normala. Skål på mig.

Skälen ovan är mina. Du kanske har dina skäl till varför du föredrar SQL-92 eller varför du hatar det. Jag undrar vad dessa skäl är. Låt mig veta i kommentarsektionen nedan.

Men vi kan inte avsluta den här artikeln utan exempel och förklaringar.

10 INNER JOIN-exempel

1. Sammanfoga 2 tabeller

Här är ett exempel på två tabeller sammanfogade med INNER JOIN i SQL-92-syntax.

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

Du anger bara de kolumner som du behöver. I exemplet ovan anges 4 kolumner. Jag vet att den är för lång än SELECT * men kom ihåg detta:det är bästa praxis.

Lägg även märke till användningen av tabellalias. Både Produkten och ProductSubcategory tabeller har en kolumn som heter [Namn ]. Om du inte anger aliaset kommer ett fel att utlösas.

Under tiden, här är motsvarande SQL-89-syntax:

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

De är desamma förutom joinvillkoret blandat i WHERE-satsen med ett AND-nyckelord. Men under huven, är de verkligen likadana? Låt oss inspektera resultatuppsättningen, STATISTICS IO och exekveringsplanen.

Se resultatuppsättningen med 9 poster:

Det är inte bara resultaten, utan resurserna som krävs av SQL Server är också desamma.

Se den logiska läsningen:

Slutligen avslöjar exekveringsplanen samma frågeplan för båda frågorna när deras QueryPlanHashes är jämlika. Lägg även märke till de markerade operationerna i diagrammet:

Baserat på resultaten är SQL Server-frågebehandlingen densamma, oavsett om det är SQL-92 eller SQL-89. Men som sagt, tydligheten i SQL-92 är mycket bättre för mig.

Figur 7 visar också en kapslad loopkoppling som används i planen. Varför? Resultatuppsättningen är liten.

2. Sammanfoga flera tabeller

Kolla in frågan nedan med tre sammanfogade tabeller.

-- 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. Composite Join

Du kan också ansluta 2 bord med 2 nycklar för att relatera det. Kolla in provet nedan. Den använder 2 anslutningsvillkor med en AND-operator.

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 Använda en kapslad loop Fysisk Join

I exemplet nedan, Produkten bordet har 9 poster – en liten uppsättning. Den sammanfogade tabellen är SalesOrderDetail – ett stort set. Query Optimizer kommer att använda en Nested Loop Join, som visas i figur 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 Använda en Merge Physical Join

I exemplet nedan används en Merge Join eftersom båda inmatningstabellerna är sorterade efter 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 med hjälp av en Hash Physical Join

Följande exempel kommer att använda en 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 Använder Adaptive Physical Join

I exemplet nedan, Säljare tabellen har ett icke-klustrat ColumnStore-index på TerritoryID kolumn. Frågeoptimeraren bestämde sig för en kapslad loopkoppling, som visas i figur 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. Två sätt att skriva om en underfråga till en INNER JOIN

Betrakta detta påstående med en kapslad underfråga:

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

Samma resultat kan komma ut om du ändrar den till en INNER JOIN, enligt nedan:

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

Ett annat sätt att skriva om det är att använda en härledd tabell som en tabellkälla för 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

Alla tre frågorna matar ut samma 48 poster.

9. Använda anslutningstips

Följande fråga använder en kapslad loop:

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

Om du vill tvinga den till en Hash-join, är detta vad som händer:

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

Observera dock att STATISTICS IO visar att prestandan blir dålig när du tvingar den till en Hash-join.

Samtidigt använder frågan nedan en 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

Så här blir det när du tvingar den till en kapslad loop:

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

När du kontrollerar STATISTICS IO för båda och tvingar den till en kapslad loop kräver mer resurser för att bearbeta frågan:

Att använda anslutningstips bör därför vara din sista utväg när du finjusterar för prestanda. Låt din SQL Server hantera det åt dig.

10. Använder INNER JOIN i UPDATE

Du kan också använda INNER JOIN i ett UPDATE-uttalande. Här är ett exempel:

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'

Eftersom det är möjligt att använda en join i en UPPDATERING, varför inte prova det med DELETE och INSERT?

SQL Join och INNER JOIN Takeaways

Så, vad är grejen med SQL-anslutning?

  • En SQL JOIN kombinerar poster med 2 eller flera tabeller för att bilda en resultatuppsättning.
  • Det finns typer av joins i SQL:INNER, OUTER och CROSS.
  • Som utvecklare eller administratör bestämmer du vilka logiska operationer eller anslutningstyper som ska användas för dina krav.
  • Å andra sidan bestämmer Query Optimizer de bästa fysiska anslutningsoperatörerna att använda. Det kan vara Nested Loop, Merge, Hash eller Adaptive.
  • Du kan använda anslutningstips för att tvinga fram vilken fysisk anslutning du ska använda, men det bör vara din sista utväg. I de flesta fall är det bättre att låta din SQL Server hantera det.
  • Att känna till de fysiska anslutningsoperatörerna hjälper dig också att finjustera frågeprestanda.
  • Dessutom kan delfrågor skrivas om med kopplingar.

Samtidigt visade det här inlägget 10 exempel på INNER JOINs. Det är inte bara exempelkoder. Några av dem innehåller också en inspektion av hur koden fungerar inifrån och ut. Det är inte bara för att hjälpa dig koda utan för att hjälpa dig att vara uppmärksam på prestanda. I slutet av dagen ska resultaten inte bara vara korrekta utan också levereras snabbt.

Vi är inte klara än. Nästa artikel kommer att behandla OUTER JOINS. Håll utkik.

Se även

SQL Joins låter dig hämta och kombinera data från mer än en tabell. Titta på den här videon för att lära dig mer om SQL Joins.


  1. Bokrecension:Benjamin Nevarez:Query Tuning &Optimization

  2. MYSQL OR vs IN prestanda

  3. Analysera PostgreSQL-tabellstatistik

  4. Hur kopierar eller importerar jag Oracle-scheman mellan två olika databaser på olika servrar?