Omskrivning af korrelerede underforespørgsler til joins
Fladgør korreleret logik til joins eller vinduesfunktioner for bedre ydeevne
Omskrivning af korrelerede underforespørgsler til joins er en gratis Forberedelse til kodeinterviews-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Forberedelse til kodeinterviews, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.
Hvorfor overhovedet omskrive
Korrelerede underforespørgsler er læselige, men kan være langsomme: Den indre forespørgsel kan blive kørt én gang pr. ydre række. Interviewere beder ofte om, at du omskriver en af dem til et join eller en vinduesfunktion for at forbedre ydeevnen.
Målet er at få det samme resultat med ét gennemløb af data i stedet for gentagne gennemgange af den indre forespørgsel.
At kende to eller tre omskrivningsmønstre og vide, hvornår hvert af dem bevarer korrektheden, er en central færdighed på mellemniveau.
Mønster 1: EXISTS til INNER JOIN
En korreleret EXISTS, der kontrollerer, om der findes mindst ét match, kan ofte omskrives til en INNER JOIN.
Men pas på: Et join kan give dublerede ydre rækker, hvis flere indre rækker matcher. Tilføj DISTINCT, eller aggregér for igen at få én række pr. ydre nøgle.
-- Correlated EXISTS
SELECT c.customer_id, c.name
FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id);
-- Join rewrite (DISTINCT avoids dupes from fan-out)
SELECT DISTINCT c.customer_id, c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;Faldgruben ved fan-out
Den mest almindelige fejl ved omskrivning er at glemme fan-out. EXISTS returnerer hver kunde én gang, uanset hvor mange ordrer kunden har. Et naivt join returnerer én række pr. ordre og får optællingerne til at vokse.
Hvis et efterfølgende trin udfører COUNT(*) eller SUM(amount) på det joinede resultat uden omhyggelig gruppering, bliver tallene forkerte.
Spørg altid: Kan joinet multiplicere rækker? Hvis ja, skal du bruge DISTINCT eller en GROUP BY til at samle dem igen.
Mønster 2: NOT EXISTS til LEFT JOIN / IS NULL
Omskrivningen til en anti-join er et sikkert interviewmønster. En korreleret NOT EXISTS bliver til en LEFT JOIN, hvor højre side er NULL.
Ydre rækker uden match får NULL-værdier på højre side; filtrering efter denne NULL-værdi beholder præcis de rækker, der ikke har noget match.
-- Correlated NOT EXISTS
SELECT c.customer_id FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o
WHERE o.customer_id = c.customer_id);
-- LEFT JOIN / IS NULL rewrite
SELECT c.customer_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE o.customer_id IS NULL;Vælg en kolonne, der ikke kan være NULL, til kontrollen
I omskrivningen med LEFT JOIN / IS NULL skal du kontrollere en kolonne på højre side, der aldrig er NULL ved et ægte match, helst joinnøglen eller primærnøglen.
Hvis du kontrollerer en kolonne, der kan indeholde NULL, kan du ikke skelne et ægte manglende match (ingen række) fra en matchet række, der blot har NULL dér. Den fejl returnerer forkerte rækker.
Hvis du bruger joinnøglen (her o.customer_id) eller o.order_id, betyder NULL med sikkerhed "ingen matchende række."
Mønster 3: Skalaraggregat til JOIN + GROUP BY
Et korreleret aggregat i SELECT kan omskrives til et join med en grupperet underforespørgsel (en afledt tabel).
Beregn aggregatet pr. gruppe én gang, og join det derefter tilbage til detaljerne. Den indre forespørgsel køres én gang i stedet for pr. række.
-- Correlated scalar aggregate
SELECT e1.name,
(SELECT MAX(e2.salary) FROM employees e2
WHERE e2.dept_id = e1.dept_id) AS dept_max
FROM employees e1;
-- Join + GROUP BY rewrite
SELECT e.name, m.dept_max
FROM employees e
JOIN (SELECT dept_id, MAX(salary) AS dept_max
FROM employees GROUP BY dept_id) m
ON m.dept_id = e.dept_id;Mønster 4: Omskrivning med en vinduesfunktion
Ofte er en vinduesfunktion den reneste omskrivning. MAX(salary) OVER (PARTITION BY dept_id) erstatter det korrelerede aggregat fuldstændigt, uden at der er brug for et join.
Den beregner gruppeværdien i ét gennemløb og bevarer alle detaljerækker. Det er som regel det svar, interviewere helst vil se i analyseforespørgsler.
SELECT name,
dept_id,
salary,
MAX(salary) OVER (PARTITION BY dept_id) AS dept_max
FROM employees;Omskrivning til største N pr. gruppe
En korreleret underforespørgsel, der vælger den øverste række pr. gruppe (salary = MAX per dept), kan omskrives elegant med ROW_NUMBER.
Partitionér efter gruppen, sortér efter målet, og behold rang 1. Brug RANK i stedet, hvis du vil have alle øverste rækker med samme værdi.
SELECT name, dept_id, salary
FROM (
SELECT name, dept_id, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id
ORDER BY salary DESC) AS rn
FROM employees
) t
WHERE rn = 1;Hvornår du ikke skal omskrive
Omskrivning er ikke altid en fordel. Behold den korrelerede underforespørgsel, når:
- Den ydre mængde er lille, så omkostningen pr. række er ubetydelig.
- Den korrelerede kolonne er godt indekseret, og optimeringsprogrammet allerede omdanner den til en effektiv semi-join.
- Læselighed er vigtigere end mikrooptimering i kode, der vedligeholdes.
Moderne optimeringsprogrammer omdanner ofte EXISTS til en semi-join automatisk. Sig, at du vil måle med EXPLAIN, før du antager, at en omskrivning hjælper.
Kontrol af ækvivalens
Efter enhver omskrivning skal du bekræfte, at den returnerer de samme rækker og den samme kardinalitet som originalen.
- Kontrollér, at rækkeantallene stemmer overens.
- Kontrollér, at et join med fan-out ikke har introduceret dubletter.
- Kontrollér, at NULL-tilfælde og tomme grupper stadig fungerer korrekt.
En hurtig metode er at køre begge versioner og bruge EXCEPT på dem i begge retninger; et tomt resultat betyder, at de stemmer overens. Interviewere værdsætter, at du kontrollerer resultatet i stedet for at antage noget.
SELECT customer_id FROM query_a
EXCEPT
SELECT customer_id FROM query_b;
-- and the reverse; both empty => equivalentOmskrivning af IN til JOIN
En ukorreleret IN-underforespørgsel kan ofte også omskrives til et join, men den samme advarsel om fan-out gælder. IN fjerner dubletter i medlemskabet, mens et join ikke gør det.
Hvis den indre liste har dublerede nøgler, gentager joinet de ydre rækker. Brug DISTINCT på den indre side eller på det endelige resultat for at matche IN-semantikken.
-- IN subquery
SELECT c.name FROM customers c
WHERE c.customer_id IN (SELECT o.customer_id FROM orders o);
-- Join rewrite, de-duplicated to match IN
SELECT DISTINCT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id;Hurtig kontrol
Vælg den korrekte join-omskrivning til en korreleret NOT EXISTS-anti-join.
Opsummering: Omskrivning af korrelerede underforespørgsler til joins
Vigtigste pointer:
EXISTS→INNER JOIN(tilføj DISTINCT for at undgå dubletter fra fan-out).NOT EXISTS→LEFT JOIN ... WHERE key IS NULL(kontrollér en kolonne, der ikke kan indeholde NULL).- Korreleret skalaraggregat →
JOINmed en grupperet afledt tabel eller endnu bedre en vinduesfunktion. - Top pr. gruppe →
ROW_NUMBER(ellerRANKved ens værdier). - Kontrollér ækvivalensen, og tjek med
EXPLAIN, før du antager, at en omskrivning er hurtigere.
At kende begge former og faldgruben ved fan-out er netop det, interviewere på mellemniveau undersøger.
Lær Forberedelse til kodeinterviews med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 90
- Lektioner
- 360
Ofte stillede spørgsmål
Er lektionen “Omskrivning af korrelerede underforespørgsler til joins” gratis?
Ja — hele teksten til “Omskrivning af korrelerede underforespørgsler til joins” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Forberedelse til kodeinterviews-kurset, skal du opgradere til CoddyKit PRO. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Omskrivning af korrelerede underforespørgsler til joins”?
Fladgør korreleret logik til joins eller vinduesfunktioner for bedre ydeevne Du øver dig i Forberedelse til kodeinterviews med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Forberedelse til kodeinterviews?
Der kræves ingen tidligere erfaring. Forberedelse til kodeinterviews på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.
Hvor lang tid tager lektionen “Omskrivning af korrelerede underforespørgsler til joins”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Forberedelse til kodeinterviews-lektion?
Ja. Alle Forberedelse til kodeinterviews-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Anatomi af en korreleret underforespørgsel
- Aggregater pr. gruppe uden GROUP BY
- Korrelerede EXISTS og NOT EXISTS
- Omskrivning af korrelerede underforespørgsler til joins