Join-fan-out och radmultiplikation
Varför en join kan returnera fler rader än någon av tabellerna och hur intervjuare testar detta
Join-fan-out och radmultiplikation är en gratis lektion i Förberedelser inför SQL-intervjun på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Förberedelser inför SQL-intervjun, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Förberedelser inför SQL-intervjun innehåller totalt 4 lektioner.
När en join returnerar för många rader
En av de mest avslöjande intervjufrågorna låter oskyldig: "kan en join returnera fler rader än den större tabellen?" Svaret är ja, och fenomenet kallas fan-out eller radmultiplicering.
Kandidater som säger "en join kombinerar bara tabeller" missar detta. Kandidater som kan förutsäga det exakta radantalet får jobbet. Den här lektionen bygger upp den förmågan.
Orsaken: en-till-många-matchningar
Fan-out uppstår när en rad till vänster matchar många rader till höger. Varje matchning skapar en separat resultat rad.
Med customers och orders har Ada (en kund) två order. Joinen producerar en rad per order, så Ada dupliceras. Kundfälten upprepas; det är bara orderfälten som skiljer sig åt.
SELECT c.name, o.amount
FROM customers c
JOIN orders o ON o.customer_id = c.id;
-- Ada appears twice (she has 2 orders)
-- name | amount
-- Ada | 50
-- Ada | 20
-- Bob | 99Räkna resultatets rader
Antalet resultatrader är lika med summan av matchningarna för varje rad till vänster, inte antalet kunder.
- Ada -> 2 order -> 2 rader
- Bob -> 1 order -> 1 rad
- Cleo -> 0 order -> 0 rader (tas bort av INNER JOIN)
Totalt = 3 rader, trots att customers också har 3 rader. Ändra Adas antal order till 10, så ökar resultatet till 11 rader.
Många-till-många exploderar
Fan-out förstärks när båda sidorna har flera matchningar för samma nyckel. Om nyckeln K förekommer 3 gånger till vänster och 4 gånger till höger producerar joinen 3 x 4 = 12 rader för den nyckeln.
Det är så en till synes liten join kan växa till miljoner rader. Intervjuare tycker om att ge dig duplicerade nycklar på båda sidorna för att se om du upptäcker multipliceringen.
-- left has 3 rows with tag 'A', right has 4 rows with tag 'A'
SELECT l.id, r.id
FROM left_t l
JOIN right_t r ON r.tag = l.tag;
-- tag 'A' alone yields 3 * 4 = 12 output rowsAggregeringsfällan
Här är det fel som intervjuare oftast planterar. Du joinar orders med order_items för att hämta artikelinformation och beräknar sedan SUM av orderbeloppet. Eftersom varje order får fan-out till flera orderrader räknas orderbeloppet en gång per orderrad.
SUM blir nu kraftigt uppblåst. Frågan ser korrekt ut och körs dessutom utan fel, vilket är det som gör den farlig.
-- BUG: order.amount duplicated across items
SELECT SUM(o.amount) AS total
FROM orders o
JOIN order_items i ON i.order_id = o.id;
-- a 3-item order counts o.amount 3 timesSå ser uppblåsningen ut
Anta att en order har beloppet 100 och tre orderrader. Joinen producerar tre rader, som alla innehåller beloppet 100. SUM(o.amount) returnerar 300, inte 100.
Lösningen är att aggregera på rätt granularitet: summera artiklarna eller summera distinkta order separat. Beräkna aldrig SUM av ett värde från den överordnade tabellen över en join med fan-out till underordnade rader.
o.id | o.amount | i.id
7 | 100 | 71
7 | 100 | 72
7 | 100 | 73
-- SUM(o.amount) = 300 (WRONG, should be 100)Lösning 1: Aggregera den underordnade tabellen först
Den renaste lösningen är att föraggregera den sida som innehåller många rader i en underfråga eller CTE, så att varje överordnad rad matchar exakt en sammanfattad rad. Ingen fan-out och ingen uppblåsning.
Här samlar vi ihop artiklarna till en rad per order innan joinen, så att den överordnade radens belopp aldrig dupliceras.
SELECT o.id, o.amount, i.item_count
FROM orders o
JOIN (
SELECT order_id, COUNT(*) AS item_count
FROM order_items
GROUP BY order_id
) i ON i.order_id = o.id;Lösning 2: COUNT(DISTINCT) och villkorade summor
Om du måste aggregera efter en join med fan-out ska du räkna eller summera på rätt granularitet. Använd COUNT(DISTINCT o.id) för att räkna order i stället för orderrader.
Observera: SUM(DISTINCT o.amount) är INTE en säker lösning, eftersom två olika order legitimt kan ha samma belopp och då slås ihop. Föraggregering är mer tillförlitlig.
SELECT COUNT(DISTINCT o.id) AS num_orders,
COUNT(i.id) AS num_items
FROM orders o
JOIN order_items i ON i.order_id = o.id;Upptäck fan-out innan det blir ett problem
Ett snabbt diagnostiskt test som intervjuare gillar är att kontrollera om joinnyckeln är unik på den sida som du förväntar dig ska vara "en". Om antalet unika nycklar är mindre än antalet rader innehåller den sidan dubbletter och kommer att skapa fan-out.
-- if this returns rows, order_id is NOT unique in order_items
SELECT order_id, COUNT(*) AS n
FROM order_items
GROUP BY order_id
HAVING COUNT(*) > 1;Verifiera granulariteten med en räkning
Gör en rimlighetskontroll av radantalet innan du litar på en aggregering över ett joinat resultat. Ett snabbt knep är att jämföra antalet joinade rader med antalet rader i den tabell som du förväntar dig definierar granulariteten.
Om COUNT(*) över joinen är större än COUNT(*) för orders har joinen skapat fan-out, och all aggregering per order är då i riskzonen. Den här kontrollen på en enda rad har räddat många intervjusvar.
-- joined rows should equal order count if no fan-out
SELECT COUNT(*) AS joined_rows
FROM orders o
JOIN order_items i ON i.order_id = o.id;
SELECT COUNT(*) AS order_rows FROM orders;
-- joined_rows > order_rows => fan-out presentFan-out är inte alltid ett fel
Ibland vill du ha en rad per underordnad post. Att lista varje orderrad tillsammans med orderhuvudet är korrekt fan-out. Färdigheten ligger i att känna till den önskade granulariteten: hur många rader ska en entitet producera?
Ange granulariteten innan du skriver frågan. "Jag vill ha en rad per orderrad" jämfört med "en rad per order" avgör om fan-out är en funktion eller ett fel.
Snabbtest
Förutsäg resultatet av en en-till-många-join.
Sammanfattning: Fan-out och radmultiplicering
Detta ska du komma ihåg:
- En join producerar en rad per matchande par, så en-till-många-matchningar duplicerar "en"-sidan.
- Många-till-många-nycklar multipliceras: 3 x 4 = 12 rader för den nyckeln.
- Om du aggregerar ett värde från den överordnade tabellen över en join med fan-out blir summor och antal uppblåsta.
- Lös problemet genom att föraggregera den underordnade tabellen eller genom att räkna och summera på rätt granularitet, till exempel med
COUNT(DISTINCT). - Ange alltid den avsedda granulariteten först; fan-out är bara ett fel när den inte överensstämmer med den.
Lär dig SQL med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”Join-fan-out och radmultiplikation” gratis?
Ja – hela texten till ”Join-fan-out och radmultiplikation” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Förberedelser inför SQL-intervjun, kan Ni uppgradera till CoddyKit PRO. Kursen i Förberedelser inför SQL-intervjun innehåller totalt 4 lektioner.
Vad lär jag mig i ”Join-fan-out och radmultiplikation”?
Varför en join kan returnera fler rader än någon av tabellerna och hur intervjuare testar detta Ni övar på Förberedelser inför SQL-intervjun med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Förberedelser inför SQL-intervjun?
Du behöver inga förkunskaper. Utbildningen i Förberedelser inför SQL-intervjun på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Join-fan-out och radmultiplikation”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Förberedelser inför SQL-intervjun-lektionen?
Ja. Varje Förberedelser inför SQL-intervjun-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Så matchar INNER JOIN rader
- ON kontra WHERE i joinar
- Join-fan-out och radmultiplikation
- Joina tre eller fler tabeller