Skrive om korrelerte underspørringer til joiner
Gjør korrelert logikk om til joiner eller window-funksjoner for bedre ytelse.
Skrive om korrelerte underspørringer til joiner er en gratis leksjon i Forberedelse til kodeintervjuer på CoddyKit. Dette er leksjon 4 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.
Hvorfor skrive om i det hele tatt
Korrelert underspørringer er lesbare, men kan være trege: den indre spørringen kan kjøres én gang per ytre rad. Intervjuere ber ofte om at De skal skrive den om til en join eller en vindusfunksjon for å forbedre ytelsen.
Målet er å få det samme resultatet med én gjennomgang av dataene i stedet for gjentatte skanninger av den indre spørringen.
Å kjenne to eller tre mønstre for omskriving, og vite når hvert av dem bevarer korrektheten, er en sentral ferdighet på mellomnivå.
Mønster 1: EXISTS til INNER JOIN
En korrelert EXISTS som tester om det finnes minst ett treff, kan ofte skrives om til en INNER JOIN.
Vær imidlertid oppmerksom på at en join kan produsere dupliserte ytre rader hvis flere indre rader samsvarer. Legg til DISTINCT eller bruk aggregering for å gjenopprette én rad per ytre nøkkel.
-- 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;Fellen med radmangedobling
Den vanligste feilen ved omskriving er å glemme radmangedobling. EXISTS returnerer hver kunde én gang, uansett hvor mange ordrer kunden har. En naiv join returnerer én rad per ordre og blåser opp opptellingene.
Hvis et senere trinn bruker COUNT(*) eller SUM(amount) på det joinede resultatet uten å gruppere nøye, blir tallene feil.
Spør alltid: Kan joinen mangedoble rader? Hvis ja, bruker De DISTINCT eller en GROUP BY for å samle resultatet tilbake.
Mønster 2: NOT EXISTS til LEFT JOIN / IS NULL
Omskriving til anti-join er et sikkert intervjumønster. En korrelert NOT EXISTS blir til en LEFT JOIN der høyresiden er NULL.
Ytre rader uten treff får NULL-verdier på høyresiden. Ved å filtrere på denne NULL-verdien beholder De nøyaktig radene uten treff.
-- 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;Velg en kolonne som ikke kan være NULL
Ved omskrivingen LEFT JOIN / IS NULL må De teste en kolonne på høyresiden som aldri er NULL ved et reelt treff, helst join-nøkkelen eller primærnøkkelen.
Hvis De tester en kolonne som kan være NULL, kan De ikke skille et ekte manglende treff (ingen rad) fra en rad som faktisk ble funnet, men som har NULL i denne kolonnen. Denne feilen returnerer feil rader.
Bruk av join-nøkkelen (her o.customer_id) eller o.order_id garanterer at NULL betyr "ingen samsvarende rad."
Mønster 3: Skalar aggregering til JOIN + GROUP BY
En korrelert aggregering i SELECT kan bli til en join mot en gruppert underspørring (en avledet tabell).
Beregn aggregeringen per gruppe én gang, og join den deretter tilbake til detaljradene. Den indre spørringen kjøres én gang i stedet for én gang per rad.
-- 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: Omskriving med vindusfunksjon
Ofte er en vindusfunksjon den ryddigste omskrivingen. MAX(salary) OVER (PARTITION BY dept_id) erstatter den korrelerte aggregeringen fullstendig, uten behov for en join.
Den beregner gruppeverdien i én gjennomgang og beholder alle detaljradene. Dette er vanligvis svaret intervjuere helst vil se for analyseforespørsler.
SELECT name,
dept_id,
salary,
MAX(salary) OVER (PARTITION BY dept_id) AS dept_max
FROM employees;Omskriving av største-N-per-gruppe
En korrelert underspørring som velger den øverste raden per gruppe (salary = MAX per dept) kan enkelt skrives om med ROW_NUMBER.
Partisjoner etter gruppen, sorter etter måltallet, og behold rangering 1. Bruk RANK i stedet hvis De vil ha med alle øverste rader med samme verdi.
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;Når De ikke bør skrive om
Omskriving er ikke alltid en forbedring. Behold den korrelerte underspørringen når:
- Det ytre datasettet er lite, slik at kostnaden per rad er ubetydelig.
- Den korrelerte kolonnen er godt indeksert, og optimalisatoren allerede gjør spørringen om til en effektiv semi-join.
- Lesbarhet er viktigere enn mikrooptimalisering i kode som skal vedlikeholdes.
Moderne optimalisatorer gjør ofte automatisk EXISTS om til en semi-join. Si at De vil måle med EXPLAIN før De antar at en omskriving hjelper.
Kontroll av ekvivalens
Etter enhver omskriving må De bekrefte at den returnerer de samme radene og samme kardinalitet som originalen.
- Kontroller at radantallet stemmer.
- Kontroller at ingen duplikater ble innført av radmangedobling i en join.
- Kontroller at NULL- og tomme gruppe-tilfeller fortsatt oppfører seg riktig.
En rask metode er å kjøre begge versjonene og bruke EXCEPT i begge retninger. Et tomt resultat betyr at de er enige. Intervjuere setter pris på at De verifiserer i stedet for å anta.
SELECT customer_id FROM query_a
EXCEPT
SELECT customer_id FROM query_b;
-- and the reverse; both empty => equivalentOmskriving av IN til en JOIN
En ukorrelert IN-underspørring kan ofte også skrives om til en join, men den samme advarselen om radmangedobling gjelder. IN fjerner duplikater ved medlemskapstesting, mens en join ikke gjør det.
Hvis den indre listen inneholder dupliserte nøkler, gjentar joinen de ytre radene. Bruk DISTINCT på den indre siden eller på det endelige resultatet for å få samme semantikk som IN.
-- 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;Hurtigsjekk
Velg riktig join-omskriving for en korrelert NOT EXISTS-anti-join.
Oppsummering: Omskriving av korrelerte underspørringer til joiner
Viktigste punkter:
EXISTS→INNER JOIN(legg til DISTINCT for å unngå duplikater fra radmangedobling).NOT EXISTS→LEFT JOIN ... WHERE key IS NULL(test en kolonne som ikke kan være NULL).- Korrelert skalar aggregering →
JOINen gruppert avledet tabell, eller enda bedre, bruk en vindusfunksjon. - Øverste rad per gruppe →
ROW_NUMBER(ellerRANKved like verdier). - Kontroller ekvivalensen, og sjekk med
EXPLAINfør De antar at en omskriving er raskere.
Å kjenne begge formene og fellen med radmangedobling er akkurat det intervjuer på mellomnivå undersøker.
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 «Skrive om korrelerte underspørringer til joiner» gratis?
Ja – hele teksten i «Skrive om korrelerte underspørringer til joiner» 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 «Skrive om korrelerte underspørringer til joiner»?
Gjør korrelert logikk om til joiner eller window-funksjoner for bedre ytelse. 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 4 av 4.
Hvor lang tid tar leksjonen «Skrive om korrelerte underspørringer til joiner»?
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
- Anatomien til en korrelert underspørring
- Aggregater per gruppe uten GROUP BY
- Korrelert EXISTS og NOT EXISTS
- Skrive om korrelerte underspørringer til joiner