Forberedelse til kodeintervjuer · leksjon

Join-algoritmer: Nested Loop, Hash og Merge

Hvordan hver join utføres, og når det er riktig å velge den.

Leksjon 3 av 413 trinn

Join-algoritmer: Nested Loop, Hash og Merge er en gratis leksjon i Forberedelse til kodeintervjuer på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Forberedelse til kodeintervjuer, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Forberedelse til kodeintervjuer inneholder totalt 4 leksjoner.

Joins er algoritmer, ikke bare syntaks

Du kjenner allerede INNER JOIN som syntaks. På seniornivå spør intervjuere hvordan databasen fysisk utfører en join. Det finnes tre algoritmer:

  • Nested Loop Join
  • Hash Join
  • Merge Join (sort-merge)

Den logiske join-typen (INNER, LEFT) er uavhengig av algoritmen. Planleggeren velger algoritme basert på tabellstørrelser, indekser og sorteringsrekkefølge. Å vite når hver av dem er best, er kjernen i denne leksjonen.

Nested Loop Join

Nested Loop er den enkleste: For hver rad i den ytre tabellen skannes den indre tabellen for å finne treff. I pseudokode er dette to løkker, der den ene ligger inni den andre.

Naivt sett er dette O(outer * inner), noe som er svært dårlig for store tabeller. Men det blir utmerket når den indre siden har en indeks på join-nøkkelen: Hver ytre rad utløser et billig indeksoppslag i stedet for en full skanning av den indre tabellen.

Dette er planleggerens favoritt når den ytre tabellen er liten og den indre join-kolonnen er indeksert.

Nested Loop  (cost=0.42..120.5 rows=15 width=72)
  ->  Seq Scan on customers c  (rows=3)
  ->  Index Scan using idx_orders_cust on orders o
        Index Cond: (o.customer_id = c.id)
        (loops=3)

Slik leser du løkker i en Nested Loop

Et tydelig kjennetegn på en nested loop er loops på den indre noden. Eksemplet viser loops=3 fordi den ytre siden produserte 3 rader, og den indre indeksskanningen derfor ble kjørt 3 ganger.

Faren oppstår når den ytre siden er stor. Hvis den ytre siden produserer 2 millioner rader, kjører den indre siden 2 millioner ganger. Selv et raskt oppslag på 0.01ms blir da 20 sekunder.

I intervjuer bør du påpeke alle nested loops der loops er høyt for en indre tabell uten en god indeks. Det er den trege spørringen.

Hash Join

Hash Join håndterer store, usorterte tabeller godt. Den kjører i to faser:

  • Build: Les den minste tabellen og last den inn i en hash-tabell i minnet, med join-kolonnen som nøkkel.
  • Probe: Skann den største tabellen. For hver rad hashes join-nøkkelen og slås opp i hash-tabellen.

Hver tabell leses bare én gang, noe som gir omtrent O(outer + inner). Det kreves verken indekser eller sortert inndata, og derfor dominerer denne algoritmen store analytiske joins på likhetsbetingelser.

Hash Join  (cost=18.0..520.0 rows=900 width=72)
  Hash Cond: (o.customer_id = c.id)
  ->  Seq Scan on orders o  (rows=100000)
  ->  Hash  (rows=500)
        ->  Seq Scan on customers c  (rows=500)

Begrensninger for Hash Join

Det er to ting du må nevne om hash joins:

  • De fungerer bare for join-betingelser med likhet (a.id = b.id). En områdebetingelse som a.x < b.y kan ikke bruke en hash join.
  • Build-siden må få plass i work_mem. Hvis den ikke gjør det, skriver Postgres batcher til disk (du vil se Batches: > 1 og diskbruk), noe som gjør joinen betydelig tregere.

En hash join med en enorm build-side og svært liten work_mem er derfor en reell ytelsesfeil som bør påpekes.

Hash  (actual rows=2000000 loops=1)
  Buckets: 65536  Batches: 16  Memory Usage: 4096kB

Merge Join

Merge Join (sort-merge) krever at begge inndataene er sortert etter join-nøkkelen. Deretter går den gjennom begge i takt, omtrent som når to sorterte lister flettes, ved å flytte pekeren som ligger etter.

Den er effektiv når inndataene allerede er sortert, for eksempel når de kommer direkte fra en indeks i nøkkelrekkefølge, fordi det ikke er nødvendig med et sorteringstrinn. Den støtter også område- og ulikhets-joins, i motsetning til hash join.

Hvis inndataene ikke er forhåndssortert, legger planleggeren til eksplisitte Sort-noder, og sorteringskostnaden kan gjøre hash join billigere i stedet.

Merge Join  (cost=0.85..210.0 rows=900 width=72)
  Merge Cond: (o.customer_id = c.id)
  ->  Index Scan using idx_orders_cust on orders o
  ->  Index Scan using customers_pkey on customers c

Huskeliste for valg

Husk når hver algoritme er best:

  • Nested Loop, en liten ytre tabell og en indeksert indre join-nøkkel; også det eneste alternativet for joins med ulikhetsbetingelser uten sortert inndata.
  • Hash Join, store usorterte tabeller som joines med likhetsbetingelser; ingen indekser er nødvendig.
  • Merge Join, når begge inndataene allerede er sortert etter nøkkelen (ofte via indekser), eller for område-joins; utmerket for svært store, forhåndssorterte datasett.

Planleggeren anslår kostnaden for hver algoritme og velger den billigste ut fra radestimatene.

Minne- og sorteringskostnader

Ressursbruken varierer kraftig, og intervjuere undersøker dette:

  • Nested Loop, bruker minimalt med minne; kostnaden domineres av gjentatte oppslag i den indre tabellen.
  • Hash Join, trenger minne til hash-tabellen; skriver til disk hvis den blir for stor.
  • Merge Join, er billig å flette, men dyr hvis den først må sortere; sorteringer bruker også work_mem og kan skrive til disk.

Å øke work_mem kan derfor gjøre en treg hash join eller sortering som skriver til disk, om til en som får plass i minnet. Det er et konkret optimaliseringssvar.

Hvorfor en Nested Loop gikk galt

Et klassisk scenario: En spørring var rask i utviklingsmiljøet, men treg i produksjon. Planen viser en Nested Loop med loops=3000000.

Planleggeren undervurderte antallet rader på den ytre siden (foreldet statistikk sa 3 rader, mens virkeligheten er 3 millioner), og valgte derfor en nested loop. Med korrekte statistikker ville den ha valgt en hash join.

Intervjusvaret ditt: Kjør ANALYZE slik at estimatet blir korrekt. Planleggeren vil da bytte til en hash join, og spørringen blir betydelig raskere.

Nested Loop  (cost=0.42..50.0 rows=3 width=72)
  ->  Seq Scan on big_outer  (actual rows=3000000 loops=1)
  ->  Index Scan on inner_t  (actual rows=1 loops=3000000)

Påvirke valget

Du bør vanligvis ikke tvinge frem algoritmer, men du kan gjøre det i testing for å sammenligne. Postgres tilbyr brytere for hver metode:

SET enable_nestloop = off; og tilsvarende for enable_hashjoin og enable_mergejoin. Slå av én av dem, kjør EXPLAIN ANALYZE på nytt, og se om alternativet faktisk er raskere.

De riktige løsningene er fortsatt ferske statistikker, de riktige indeksene, tilstrekkelig work_mem og selektive predikater. Tvang er bare til diagnostisering.

SET enable_nestloop = off;
EXPLAIN ANALYZE
SELECT * FROM orders o JOIN customers c ON o.customer_id = c.id;
SET enable_nestloop = on;

Oppsummering: Joins i stor skala

Sett dette sammen for en analytisk arbeidsbelastning som joiner to store fakta- og dimensjonstabeller på en id:

  • Hvis dimensjonstabellen får plass i minnet, kan du forvente en Hash Join, som ofte er best.
  • Hvis begge tabellene kommer sortert fra indekser, kan en Merge Join unngå å bygge en hash-tabell.
  • En Nested Loop her ville vært et varselstegn, vanligvis forårsaket av et feilaktig estimat.

Å lese hvilken algoritme planleggeren valgte, og vurdere om den burde ha valgt den, er nettopp seniorferdigheten disse spørsmålene tester.

Hurtigsjekk

Du joiner to store, usorterte tabeller med en likhetsbetingelse a.id = b.id. Ingen av dem har en nyttig indeks, og statistikken er korrekt. Hvilken join-algoritme vil planleggeren mest sannsynlig velge?

Oppsummering

De tre join-algoritmene:

  • Nested Loop, ytre rad ganger indre oppslag; utmerket med en liten ytre tabell og en indeksert indre nøkkel, men farlig når loops er svært høyt.
  • Hash Join, bygg og slå opp; best for store, usorterte joins med likhetsbetingelser, begrenset til likhet og avhengig av work_mem.
  • Merge Join, går parallelt gjennom sorterte inndata; ideell når dataene allerede er sortert eller for område-joins.

Planleggeren velger basert på kostnad og statistikk. En overraskende nested loop med svært mange løkker betyr nesten alltid et feilaktig radestimat. Rett statistikken.

Gratis å komme i gang

Lær deg Forberedelse til kodeintervjuer med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
90
Leksjoner
360

Ofte stilte spørsmål

Er leksjonen «Join-algoritmer: Nested Loop, Hash og Merge» gratis?

Ja – hele teksten i «Join-algoritmer: Nested Loop, Hash og Merge» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Forberedelse til kodeintervjuer-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Forberedelse til kodeintervjuer inneholder totalt 4 leksjoner.

Hva lærer jeg i «Join-algoritmer: Nested Loop, Hash og Merge»?

Hvordan hver join utføres, og når det er riktig å velge den. Du øver på Forberedelse til kodeintervjuer med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Forberedelse til kodeintervjuer?

Ingen tidligere erfaring er nødvendig. Forberedelse til kodeintervjuer på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Join-algoritmer: Nested Loop, Hash og Merge»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Forberedelse til kodeintervjuer-leksjonen?

Ja. Alle Forberedelse til kodeintervjuer-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Lese en EXPLAIN-plan
  2. Seq Scan, Index Scan eller Index-Only
  3. Join-algoritmer: Nested Loop, Hash og Merge
  4. Finne og utbedre trege spørringer
← Tilbake til Forberedelse til kodeintervjuer