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

Din ultimative guide til SQL Join:INNER JOIN – Del 1

Indre sammenføjning, ydre sammenføjning, krydsforbindelse? Hvad giver?

Det er et gyldigt spørgsmål. Jeg så engang en Visual Basic-kode med T-SQL-koder indlejret i den. VB-koden henter tabelposter med flere SELECT-sætninger, en SELECT* pr. tabel. Derefter kombinerer den flere resultatsæt til et rekordsæt. Absurd?

For de unge udviklere, der gjorde det, var det ikke. Men da de bad mig om at vurdere, hvorfor systemet var langsomt, var det spørgsmål det første, der fangede min opmærksomhed. Det er rigtigt. De har aldrig hørt om SQL joins. Retfærdigt over for dem var de ærlige og åbne over for forslag.

Hvordan beskriver du SQL joins? Måske husker du én sang – Forestil dig af John Lennon:

Du kan sige, at jeg er en drømmer, men jeg er ikke den eneste.

Jeg håber, at du en dag slutter dig til os, og at verden vil være som én.

I sangens sammenhæng er joining at forene. I en SQL-database danner kombination af poster med 2 eller flere tabeller i ét resultatsæt en joinforbindelse .

Denne artikel er starten på en 3-delt serie, der taler om SQL joins:

  • INDRE JOIN
  • YDRE JOIN, som inkluderer LEFT, RIGHT og FULL
  • KRYDSJOIN

Men før vi begynder at diskutere INNER JOIN, lad os beskrive joinforbindelser generelt.

Mere om SQL JOIN

Joins vises lige efter FROM-klausulen. I sin enkleste form ser det ud til at bruge SQL-92-standarden:

FRA [] JOIN [] [ON ] [ JOIN [] [ON ] JOIN [] [ON ]][WHERE ]

Lad os beskrive de daglige ting omkring JOIN.

Tabelkilder

Du kan tilføje op til 256 tabelkilder ifølge Microsoft. Det afhænger selvfølgelig af dine serverressourcer. Jeg har aldrig deltaget i mere end 10 borde i mit liv, for ikke at nævne 256. Under alle omstændigheder kan tabelkilder være en af ​​følgende:

  • Tabel
  • Vis
  • Tabel eller visningssynonym
  • Tabelvariabel
  • Tabelvurderet funktion
  • Afledt tabel

Tabelalias

Et alias er valgfrit, men det forkorter din kode og minimerer indtastning. Det hjælper dig også med at undgå fejl, når et kolonnenavn findes i to eller flere tabeller, der bruges i en SELECT, UPDATE, INSERT eller DELETE. Det tilføjer også klarhed til din kode. Det er valgfrit, men jeg vil anbefale at bruge aliaser. (Medmindre du elsker at skrive tabelkilder efter navn.)

Deltagelsesbetingelse

Nøgleordet ON går forud for sammenkædningsbetingelsen, der kan være en enkelt sammenkædning eller 2-nøglekolonner fra de to sammenføjede tabeller. Eller det kan være en sammensat join, der bruger mere end 2 nøglekolonner. Det definerer, hvordan tabeller er relateret.

Sammenføjningsbetingelsen bruger vi dog kun til INDRE og YDRE sammenføjninger. Brug af det på en CROSS JOIN vil udløse en fejl.

Da sammenføjningsbetingelser definerer relationerne, har de brug for operatører.

Den mest almindelige af joinbetingelsesoperatorer er lighedsoperator (=). Andre operatører som> eller

SQL JOIN vs. underforespørgsler

De fleste joinforbindelser kan omskrives som underforespørgsler og omvendt. Tjek denne artikel for at lære mere om underforespørgsler sammenlignet med joinforbindelser.

Joins og afledte tabeller

Brug af afledte tabeller i en join ser sådan ud:

FRA tabel1 aINNER JOIN (VÆLG y.column3 fra tabel2 x INNER JOIN tabel3 y on x.column1 =y.column1) b ON a.col1 =b.col2 

Den tilslutter sig fra resultatet af en anden SELECT-sætning, og den er fuldkommen gyldig.

Du vil have flere eksempler, men lad os beskæftige os med en sidste ting om SQL JOINS. Det er, hvordan SQL Servers Query Optimizer-processer forbindes.

Hvordan SQL Server behandler joinforbindelser

For at forstå, hvordan processen fungerer, skal du vide om de to typer operationer, der er involveret:

  • Logiske handlinger svarer til de jointyper, der bruges i en forespørgsel:INNER, OUTER eller CROSS. Du, som udvikler, definerer denne del af behandlingen, når du laver forespørgslen.
  • Fysiske operationer – Query Optimizer vælger den bedste fysiske handling, der er relevant for din tilslutning. Den bedste betyder, at den hurtigste giver resultater. Udførelsesplanen for din forespørgsel vil vise de valgte fysiske join-operatører. Disse operationer er:
    • Indlejret løkkeforbindelse. Denne operation er hurtig, hvis en af ​​de to tabeller er lille, og den anden er stor og indekseret. Det kræver mindst I/O med færrest sammenligninger, men det er ikke godt for store resultatsæt.
    • Flet tilmelding. Dette er den hurtigste handling for store og sorterede resultatsæt efter kolonner, der bruges i joinforbindelsen.
    • Hash Join. Forespørgselsoptimeringsværktøjet bruger det, når resultatsættet er for stort til en indlejret sløjfe, og inputs er usorteret til en fletsammenføjning. En hash er mere effektiv end at sortere den først og anvende en Merge join.
    • Adaptive Join. Fra og med SQL Server 2017 muliggør den valget mellem en indlejret løkke eller hash . Sammenføjningsmetoden udskydes, indtil det første input er scannet. Denne handling skifter dynamisk til en bedre fysisk joinforbindelse uden genkompilering.

Hvorfor skal vi bøvle med dette?

Et ord:Ydeevne.

En ting er at vide, hvordan man danner forespørgsler med joins for at producere korrekte resultater. En anden er at få det til at køre så hurtigt som muligt. Du skal være ekstra bekymret over dette, hvis du vil have et godt omdømme hos dine brugere.

Så hvad skal du være opmærksom på i udførelsesplanen for disse logiske operationer?

  • Antag, at en sorteringsoperator går forud for sammenføjningen . Denne slags operation er dyr for store borde (figur 2). Du kan rette dette ved at forhåndssortere inputtabellerne i joinforbindelsen.
  • Antag, at der er dubletter i inputtabellerne for en Merge join . SQL Server vil skrive dubletterne af den anden tabel ind i en WorkTable i tempdb. Så vil den foretage sammenligningerne der. STATISTIK IO vil afsløre alle involverede arbejdstabeller.
  • Når store data spildes til tempdb i en Hash-jo i, vil STATISTICS IO afsløre en stor logisk læsning på WorkFiles eller WorkTables. Der vises også en advarsel i udførelsesplanen (figur 3). Du kan anvende to ting:Forsortér inputtabellerne eller formindsk joinforbindelserne, hvis det er muligt. Som følge heraf kan Query Optimizer vælge en anden fysisk deltagelse.

Deltag-tip

Join-tip er nyt i SQL Server 2019. Når du bruger det i dine joins, fortæller det, at forespørgselsoptimeringsværktøjet stopper med at beslutte, hvad der er bedst for forespørgslen. Du er chefen, når det kommer til den fysiske forbindelse til brug.

Hold nu op, lige der. Sandheden er, at forespørgselsoptimeringsværktøjet typisk vælger den bedste fysiske joinforbindelse til din forespørgsel. Hvis du ikke ved, hvad du laver, skal du ikke bruge tip til at deltage.

De mulige tip, du kan angive, er LOOP, MERGE, HASH eller REMOTE.

Jeg har ikke brugt hints om joinforbindelser, men her er syntaksen:

JOIN [] TIL

Alt om INNER JOIN

INNER JOIN returnerer rækkerne med matchende poster i begge tabeller, baseret på en betingelse. Det er også standardtilslutningen, hvis du ikke angiver søgeordet INNER:

Som du kan se, matchende rækker fra Tabel1 og Tabel 2 returneres med Nøgle1 som sammenføjningsbetingelse. Tabel1 rekord med Nøgle1 ='C' er udelukket, fordi der ikke er nogen matchende poster i Tabel2 .

Når jeg danner en forespørgsel, er mit første valg INNER JOIN. OUTER JOIN kommer, når kravene kun dikterer det.

INNER JOIN-syntaks

Der er to INNER JOIN-syntaks understøttet i T-SQL:SQL-92 og SQL-89.

SQL-92 INNER JOIN

FRA []INNER JOIN [] ON [INNER JOIN [] ON INNER JOIN
[] PÅ ][Hvor ]

SQL-89 INNER JOIN

FRA [alias1], [alias2] [, [alias3], [aliasN]]HVOR ()[OG ( )AND ()AND ()]

Hvilken INNER JOIN-syntaks er bedre?

Den første join-syntaks, jeg lærte, var SQL-89. Da SQL-92 endelig ankom, tænkte jeg, at den var for lang. Jeg tænkte også, da outputtet var det samme, hvorfor skulle jeg så bekymre mig om at skrive flere søgeord? En grafisk forespørgselsdesigner havde den genererede kode SQL-92, og jeg ændrede den tilbage til SQL-89. Men i dag foretrækker jeg SQL-92, selvom jeg skal skrive mere. Her er grunden:

  • Intentionen med typen af ​​joinforbindelse er klar. Den næste fyr eller pige, der vil vedligeholde min kode, ved, hvad der er meningen med forespørgslen.
  • Hvis du glemmer joinbetingelsen i en SQL-92-syntaks, udløses en fejl. I mellemtiden vil glemme join-betingelsen i SQL-89 blive behandlet som en CROSS JOIN. Hvis jeg mente en INNER eller OUTER join, ville det være en umærkelig logisk fejl, indtil brugerne klager.
  • Nye værktøjer er mere tilbøjelige til SQL-92. Hvis jeg nogensinde bruger en grafisk forespørgselsdesigner igen, behøver jeg ikke ændre den til SQL-89. Jeg er ikke længere stædig, så min puls er normal igen. Skål for mig.

Årsagerne ovenfor er mine. Du har måske dine grunde til, hvorfor du foretrækker SQL-92, eller hvorfor du hader det. Jeg spekulerer på, hvad de grunde er. Fortæl mig det i kommentarfeltet nedenfor.

Men vi kan ikke afslutte denne artikel uden eksempler og forklaringer.

10 INNER JOIN-eksempler

1. Sammenføjning af 2 tabeller

Her er et eksempel på 2 tabeller sammenføjet ved hjælp af INNER JOIN i SQL-92-syntaks.

-- Vis veste, hjelme og lette produkter BRUG AdventureWorksGOSELECT p.ProductID,P.Name AS [Product],ps.ProductSubcategoryID,ps.Name AS [ProductSubCategory]FRA Production.Product PINNER JOIN Production.ProductSubcategory ps ON P.ProductSubcategoryID =ps.ProductSubcategoryIDWHERE P.ProductSubcategoryID IN (25, 31, 33); -- for vest, hjelm og lys -- produktunderkategorier

Du angiver kun de kolonner, du har brug for. I ovenstående eksempel er der angivet 4 kolonner. Jeg ved, at den er for lang end SELECT *, men husk dette:det er bedste praksis.

Bemærk også brugen af ​​tabelaliasser. Både Produktet og ProductSubcategory tabeller har en kolonne med navnet [Navn ]. Hvis du ikke angiver aliaset, udløses en fejl.

I mellemtiden er her den tilsvarende SQL-89-syntaks:

-- Displayveste, hjelme og lette produkter BRUG AdventureWorksGOSELECT p.ProductID,P.Name AS [Product],ps.ProductSubcategoryID,ps.Name AS [ProductSubCategory]FROM Production.Product p, Production.ProductSubcategory ps WHERE P.ProductSubcategoryID =ps.ProductSubcategoryIDAND P.ProductSubcategoryID IN (25, 31, 33);

De er de samme med undtagelse af join-betingelsen blandet i WHERE-udtrykket med et AND-nøgleord. Men under motorhjelmen, er de virkelig ens? Lad os inspicere resultatsættet, STATISTICS IO og eksekveringsplanen.

Se resultatsættet med 9 poster:

Det er ikke kun resultaterne, men de ressourcer, der kræves af SQL Server, er også de samme.

Se den logiske læsning:

Endelig afslører eksekveringsplanen den samme forespørgselsplan for begge forespørgsler, når deres QueryPlanHashes er lige. Bemærk også de fremhævede handlinger i diagrammet:

Baseret på resultaterne er SQL Server-forespørgselsbehandling den samme, uanset om det er SQL-92 eller SQL-89. Men som sagt er klarheden i SQL-92 meget bedre for mig.

Figur 7 viser også en Nested Loop Join brugt i planen. Hvorfor? Resultatsættet er lille.

2. Sammenføjning af flere borde

Tjek forespørgslen nedenfor ved hjælp af 3 sammenføjede tabeller.

-- Få det samlede antal ordrer pr. produktkategoriUSE AdventureWorksGOSELECT ps.Name AS ProductSubcategory,SUM(sod.OrderQuty) AS TotalOrdersFROM Production.Product pinner JOIN Sales.SalesOrderDetail sod ON P.ProductID =sod.ProductIDINNER JOIN Sales.SalesOrderHeader soh PÅ sod.SalesOrderID =soh.SalesOrderIDINNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID =ps.ProductSubcategoryIDWHERE soh.OrderDate MELLEM '1/1/2014/2014/Subcat.Id. 1,2)GRUPPE EFTER ps.NameHAVING ps.Name IN ('Mountain Bikes', 'Road Bikes')

3. Composite Join

Du kan også forbinde 2 borde ved at bruge 2 nøgler til at relatere det. Se eksemplet nedenfor. Den bruger 2 joinbetingelser med en AND-operator.

VÆLG a.column1,b.column1,b.column2FROM Table1 aINNER JOIN Tabel2 b PÅ a.column1 =b.column1 OG a.column2 =b.column2 

4. INNER JOIN Brug af en Nested Loop Physical Join

I eksemplet nedenfor er Produktet bordet har 9 poster - et lille sæt. Den samlede tabel er SalesOrderDetail – et stort sæt. Query Optimizer vil bruge en Nested Loop Join, som vist i figur 8.

BRUG AdventureWorksGOSELECT sod.SalesOrderDetailID,sod.ProductID,P.Name,P.ProductNumber,sod.OrderQtyFROM Sales.SalesOrderDetail sodINNER JOIN Production.Product p ON sod.ProductID =p.ProductIDWHERE P.Products(subcategoryIDSINNER , 31, 33);

5. INNER JOIN Brug af en Merge Physical Join

Eksemplet nedenfor bruger en Merge Join, fordi begge inputtabeller er sorteret efter SalesOrderID.

VÆLG soh.SalesOrderID,soh.OrderDate,sod.SalesOrderDetailID,sod.ProductID,sod.LineTotalFROM Sales.SalesOrderHeader sohINNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID =sod.SalesOrderID
 

6. INNER JOIN Brug af en Hash Physical Join

Følgende eksempel vil bruge en Hash Join:

SELECT s.Name AS Store,SUM(soh.TotalDue) AS TotalSalesFROM Sales.SalesOrderHeader sohINNER JOIN Sales.Store s ON soh.SalesPersonID =s.SalesPersonIDGROUP BY s.Name 

7. INNER JOIN Bruger Adaptive Physical Join

I eksemplet nedenfor er Sælger tabellen har et ikke-klynget ColumnStore Index på TerritoryID kolonne. Query Optimizer besluttede sig for en Nested Loop Join, som vist i figur 11.

SELECTsp.BusinessEntityID,sp.SalesQuota,st.Name AS TerritoryFROM Sales.SalesPerson spinner JOIN Sales.SalesTerritory st PÅ sp.TerritoryID =st.TerritoryIDWHERE sp.TerritoryID MELLEM 1 OG 5 

8. To måder at omskrive en underforespørgsel til en INNER JOIN

Overvej denne sætning med en indlejret underforespørgsel:

VÆLG [SalesOrderID], [OrderDate], [ShipDate], [CustomerID]FRA Sales.SalesOrderHeader HVOR [Kunde-ID] IN (VÆLG [Kunde-ID] FRA Salg.Kunde HVOR Person-ID IN (VÆLG BusinessEntityID FRA Person.Person) WHERE efternavn LIKE N'I%' OG PersonType='SC'))

De samme resultater kan komme ud, hvis du ændrer den til en INNER JOIN, som nedenfor:

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

En anden måde at omskrive den på er ved at bruge en afledt tabel som en tabelkilde for INNER JOIN:

SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]FROM Sales.SalesOrderHeader oINNER 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' OG p.LastName LIKE N'I%') AS q ON o.CustomerID =q.CustomerID 

Alle 3 forespørgsler udsender de samme 48 poster.

9. Brug af Join Hints

Følgende forespørgsel bruger en Nested Loop:

SELECT sod.SalesOrderDetailID,sod.ProductID,P.Name,P.ProductNumber,sod.OrderQtyFROM Sales.SalesOrderDetail sodINNER JOIN Production.Product p ON sod.ProductID =p.ProductIDWHERE P.ProductSubcategoryID IN(25, 31, 33);

Hvis du vil tvinge det til en Hash-joint, er det, hvad der sker:

VÆLG sod.SalesOrderDetailID,sod.ProductID,P.Name,P.ProductNumber,sod.OrderQtyFROM Sales.SalesOrderDetail sodINNER HASH JOIN Production.Product p ON sod.ProductID =p.ProductIDWHERE P.Product IN(25egoryID) , 31, 33); 

Bemærk dog, at STATISTICS IO viser, at ydeevnen bliver dårlig, når du tvinger den til en Hash-join.

I mellemtiden bruger forespørgslen nedenfor en Merge Join:

VÆLG soh.SalesOrderID,soh.OrderDate,sod.SalesOrderDetailID,sod.ProductID,sod.LineTotalFROM Sales.SalesOrderHeader sohINNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID =sod.SalesOrderID
 

Her er, hvad det bliver, når du tvinger det til en indlejret løkke:

SELECT soh.SalesOrderID,soh.OrderDate,sod.SalesOrderDetailID,sod.ProductID,sod.LineTotalFROM Sales.SalesOrderHeader sohINNER LOOP JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID =sod.SalgOrder 

Når du tjekker STATISTICS IO for begge, kræver det flere ressourcer at behandle forespørgslen at tvinge den til en Nested Loop:

Derfor bør brug af jointip være din sidste udvej, når du justerer for ydeevne. Lad din SQL Server klare det for dig.

10. Brug af INNER JOIN i OPDATERING

Du kan også bruge INNER JOIN i en UPDATE-erklæring. Her er et eksempel:

OPDATERING Sales.SalesOrderHeaderSET ShipDate =getdate() FRA Sales.SalesOrderHeader oINNER JOIN Sales.Customer c on o.CustomerID =c.CustomerIDINNER JOIN Person.Person p ON c.PersonID =p.BusinessHEREyp. 'SC' 

Da det er muligt at bruge et join i en OPDATERING, hvorfor så ikke prøve det med DELETE og INSERT?

SQL Join og INNER JOIN Takeaways

Så hvad er det store ved SQL join?

  • En SQL JOIN kombinerer poster med 2 eller flere tabeller for at danne ét resultatsæt.
  • Der er typer joins i SQL:INNER, OUTER og CROSS.
  • Som udvikler eller administrator bestemmer du, hvilke logiske operationer eller jointyper du vil bruge til dine behov.
  • På den anden side bestemmer Query Optimizer de bedste fysiske join-operatører, der skal bruges. Det kan være Nested Loop, Merge, Hash eller Adaptive.
  • Du kan bruge tip til at deltage til at tvinge hvilken fysisk deltagelse du skal bruge, men det bør være din sidste udvej. I de fleste tilfælde er det bedre at lade din SQL Server håndtere det.
  • Kendskab til de fysiske join-operatører hjælper dig også med at justere forespørgselsydeevnen.
  • Underforespørgsler kan også omskrives ved hjælp af joinforbindelser.

I mellemtiden viste dette indlæg 10 eksempler på INNER JOINs. Det er ikke kun prøvekoder. Nogle af dem indeholder også en inspektion af, hvordan koden fungerer indefra og ud. Det er ikke kun for at hjælpe dig med at kode, men for at hjælpe dig med at være opmærksom på ydeevne. I slutningen af ​​dagen skal resultaterne ikke bare være korrekte, men også leveres hurtigt.

Vi er ikke færdige endnu. Den næste artikel vil omhandle OUTER JOINS. Følg med.

Se også

SQL Joins giver dig mulighed for at hente og kombinere data fra mere end én tabel. Se denne video for at lære mere om SQL Joins.


  1. Hvordan sikkerhedskopierer man en postgresql-database fra psql?

  2. udskriv start- og slutdato i én række for kontinuerlige eller overlappende datointervaller i oracle SQL

  3. Sådan eksporteres resultaterne af en forespørgsel ved hjælp af MySQL Workbench

  4. Oracle dato