Korrelierte Unterabfragen als JOINs umschreiben
Korrelationen für bessere Performance in JOINs oder Fensterfunktionen umwandeln
Korrelierte Unterabfragen als JOINs umschreiben ist eine kostenlose SQL Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des SQL Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Warum überhaupt umschreiben
Korrelierte Unterabfragen sind gut lesbar, können aber langsam sein: Die innere Abfrage wird möglicherweise einmal pro äußerer Zeile ausgeführt. Interviewer bitten Sie häufig, eine Unterabfrage als Join oder Fensterfunktion umzuschreiben, um die Performance zu verbessern.
Das Ziel ist dasselbe Ergebnis mit einem einzigen Durchlauf über die Daten statt mit wiederholten Scans der inneren Abfrage.
Zwei oder drei Umschreibungsmuster zu kennen und zu wissen, wann jedes davon die Korrektheit bewahrt, ist eine zentrale Fähigkeit auf mittlerem Niveau.
Muster 1: EXISTS zu INNER JOIN
Ein korreliertes EXISTS, das mindestens einen Treffer prüft, kann häufig in einen INNER JOIN umgewandelt werden.
Vorsicht: Ein Join kann doppelte äußere Zeilen erzeugen, wenn mehrere innere Zeilen übereinstimmen. Fügen Sie DISTINCT hinzu oder aggregieren Sie, um wieder eine Zeile pro äußerem Schlüssel zu erhalten.
-- 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;Die Fan-out-Falle
Der häufigste Fehler beim Umschreiben besteht darin, den Fan-out zu vergessen. EXISTS gibt jeden Kunden unabhängig von der Anzahl seiner Bestellungen genau einmal zurück. Ein naiver Join gibt dagegen eine Zeile pro Bestellung zurück und lässt Zählungen zu groß erscheinen.
Wenn ein nachgelagerter Schritt COUNT(*) oder SUM(amount) über diesem Join-Ergebnis ausführt, ohne sorgfältig zu gruppieren, sind die Zahlen falsch.
Fragen Sie sich immer: Kann der Join die Anzahl der Zeilen vervielfachen? Wenn ja, verwenden Sie DISTINCT oder ein GROUP BY, um wieder eine Zeile pro Schlüssel zu erhalten.
Muster 2: NOT EXISTS zu LEFT JOIN / IS NULL
Die Umschreibung als Anti-Join ist ein bewährtes Muster in Vorstellungsgesprächen. Ein korreliertes NOT EXISTS wird zu einem LEFT JOIN, bei dem die rechte Seite NULL ist.
Nicht passende äußere Zeilen erhalten auf der rechten Seite NULL-Werte; die Filterung nach diesem NULL-Wert behält genau die Zeilen ohne Treffer.
-- 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;Wählen Sie eine NOT-NULL-Spalte zum Testen
Prüfen Sie bei der Umschreibung mit LEFT JOIN / IS NULL eine Spalte auf der rechten Seite, die bei einem echten Treffer niemals NULL ist, idealerweise den Join-Schlüssel oder den Primärschlüssel.
Wenn Sie eine NULL-fähige Spalte prüfen, können Sie einen echten Nichttreffer (keine Zeile) nicht von einer passenden Zeile unterscheiden, die dort einfach NULL enthält. Dieser Fehler liefert falsche Zeilen.
Die Verwendung des Join-Schlüssels (hier o.customer_id) oder von o.order_id garantiert, dass NULL „keine passende Zeile“ bedeutet.
Muster 3: Skalares Aggregat zu JOIN + GROUP BY
Ein korreliertes Aggregat in SELECT kann zu einem Join mit einer gruppierten Unterabfrage (einer abgeleiteten Tabelle) werden.
Berechnen Sie das Aggregat pro Gruppe einmal und verbinden Sie es anschließend wieder mit den Detailzeilen. Die innere Abfrage wird nur einmal statt pro Zeile ausgeführt.
-- 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;Muster 4: Die Umschreibung mit einer Fensterfunktion
Oft ist eine Fensterfunktion die klarste Umschreibung. MAX(salary) OVER (PARTITION BY dept_id) ersetzt das korrelierte Aggregat vollständig; ein Join ist nicht erforderlich.
Sie berechnet den Gruppenwert in einem einzigen Durchlauf und behält jede Detailzeile bei. Für Analyseabfragen ist dies normalerweise die Lösung, die Interviewer am liebsten sehen.
SELECT name,
dept_id,
salary,
MAX(salary) OVER (PARTITION BY dept_id) AS dept_max
FROM employees;Umschreibung für das größte N pro Gruppe
Eine korrelierte Unterabfrage, die die oberste Zeile pro Gruppe auswählt (salary = MAX per dept), lässt sich elegant mit ROW_NUMBER umschreiben.
Partitionieren Sie nach der Gruppe, sortieren Sie nach der Kennzahl und behalten Sie Rang 1. Verwenden Sie stattdessen RANK, wenn Sie alle obersten Zeilen mit gleichem Rang benötigen.
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;Wann Sie nicht umschreiben sollten
Eine Umschreibung ist nicht immer ein Gewinn. Behalten Sie die korrelierte Unterabfrage bei, wenn:
- Die äußere Ergebnismenge sehr klein ist, sodass die Kosten pro Zeile vernachlässigbar sind.
- Die korrelierte Spalte gut indiziert ist und der Abfrageoptimierer sie bereits in einen effizienten Semi-Join umwandelt.
- Lesbarkeit im gepflegten Code wichtiger ist als Mikrooptimierung.
Moderne Abfrageoptimierer wandeln EXISTS häufig automatisch in einen Semi-Join um. Sagen Sie, dass Sie zunächst mit EXPLAIN messen würden, bevor Sie annehmen, dass eine Umschreibung hilft.
Äquivalenz überprüfen
Bestätigen Sie nach jeder Umschreibung, dass sie dieselben Zeilen und dieselbe Kardinalität wie das Original zurückgibt.
- Prüfen Sie, ob die Zeilenzahlen übereinstimmen.
- Prüfen Sie, dass durch Fan-out des Joins keine Duplikate eingeführt wurden.
- Prüfen Sie, ob NULL- und Randfälle mit leeren Gruppen weiterhin korrekt funktionieren.
Ein schneller Weg: Führen Sie beide Varianten aus und bilden Sie in beide Richtungen EXCEPT; ein leeres Ergebnis bedeutet, dass sie übereinstimmen. Interviewer schätzen, dass Sie überprüfen statt anzunehmen.
SELECT customer_id FROM query_a
EXCEPT
SELECT customer_id FROM query_b;
-- and the reverse; both empty => equivalentIN zu einem JOIN umschreiben
Eine unkorrelierte IN-Unterabfrage lässt sich häufig ebenfalls in einen Join umschreiben, aber die gleiche Fan-out-Warnung gilt. IN entfernt doppelte Mitgliedschaften; ein Join tut dies nicht.
Wenn die innere Liste doppelte Schlüssel enthält, wiederholt der Join die äußeren Zeilen. Verwenden Sie auf der inneren Seite oder im Endergebnis DISTINCT, um die Semantik von IN beizubehalten.
-- 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;Kurzer Check
Wählen Sie die korrekte Umschreibung als Join für einen korrelierten NOT-EXISTS-Anti-Join.
Zusammenfassung: Korrelierte Unterabfragen als Joins umschreiben
Die wichtigsten Punkte:
EXISTS→INNER JOIN(fügen Sie DISTINCT hinzu, um Duplikate durch Fan-out zu vermeiden).NOT EXISTS→LEFT JOIN ... WHERE key IS NULL(prüfen Sie eine nicht NULL-fähige Spalte).- Korrelierte skalare Aggregate →
JOINmit einer gruppierten abgeleiteten Tabelle oder, noch besser, eine Fensterfunktion. - Oberste Zeilen pro Gruppe →
ROW_NUMBER(oderRANKbei gleichen Rängen). - Überprüfen Sie die Äquivalenz und verwenden Sie
EXPLAIN, bevor Sie annehmen, dass eine Umschreibung schneller ist.
Beide Formen und die Fan-out-Falle zu kennen, ist genau das, was in Vorstellungsgesprächen auf mittlerem Niveau geprüft wird.
Lerne SQL mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 30
- Lektionen
- 120
Häufig gestellte Fragen
Ist die Lektion „Korrelierte Unterabfragen als JOINs umschreiben“ kostenlos?
Ja — der vollständige Text von „Korrelierte Unterabfragen als JOINs umschreiben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des SQL Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der SQL Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Korrelierte Unterabfragen als JOINs umschreiben“?
Korrelationen für bessere Performance in JOINs oder Fensterfunktionen umwandeln Du übst SQL Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um SQL Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. SQL Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Korrelierte Unterabfragen als JOINs umschreiben“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser SQL Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede SQL Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Aufbau einer korrelierten Unterabfrage
- Aggregierte Werte pro Gruppe ohne GROUP BY
- Korrelierte EXISTS- und NOT-EXISTS-Abfragen
- Korrelierte Unterabfragen als JOINs umschreiben