In SQL beschreiben Sie, was Sie erhalten möchten, und nicht, wie es ausgefĂŒhrt werden soll. Daher nimmt das Problem der Entwicklung von SQL-Abfragen im Stil von âwie es sich anhört, so wird es geschriebenâ seinen Platz ein, zusammen mit .
Heute schauen wir uns an einfachen Beispielen an, zu was das im Kontext der Verwendung fĂŒhren kann. GROUP/DISTINCT und LIMIT gemeinsam mit ihnen.
Wenn Sie in der Abfrage geschrieben haben, âverbinde zuerst diese Tabellen und werfe dann alle Duplikate weg, es soll nur ein Exemplar pro SchlĂŒssel ĂŒbrig bleibenâ â genau so wird es funktionieren, auch wenn die Verbindung nicht nötig war.
Und manchmal hat man GlĂŒck und es âfunktioniert einfachâ, manchmal wirkt es sich negativ auf die Leistung aus, und manchmal fĂŒhrt es zu absolut unerwarteten Effekten aus Sicht des Entwicklers.

Nun, vielleicht nicht so spektakulĂ€r, aberâŠ
âSĂŒĂes Paarâ: JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition; Es ist klar, dass man solche DatensĂ€tze X auswĂ€hlen wollte, fĂŒr die es in Y VerknĂŒpfungen gibt, die mit der ausgefĂŒhrten Bedingung ĂŒbereinstimmen.Sie haben die Anfrage ĂŒber JOIN â haben mehrmals einige pk-Werte erhalten (genau so oft, wie passende EintrĂ€ge in Y vorhanden waren). Wie kann man das beheben? NatĂŒrlich DISTINCT!
Besonders Ă€rgerlich ist es, wenn fĂŒr jeden X-Eintrag mehrere Hundert verwandte Y-EintrĂ€ge gefunden werden, die dann heldenhaft Duplikate entfernt werdenâŠ

Wie kann man das beheben? ZunĂ€chst einmal sollte man erkennen, dass die Aufgabe modifiziert werden kann zu âsolche X-EintrĂ€ge auszuwĂ€hlen, fĂŒr die es in Y MINDESTENS EINEN verwandten Eintrag gibt, der den Bedingungen entsprichtâ â denn aus dem Y-Eintrag benötigen wir nichts.
Verschachteltes EXISTS
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
); Einige Versionen von PostgreSQL verstehen, dass es ausreicht, den ersten gefundenen Eintrag in EXISTS zu finden, Àltere tun das nicht. Deshalb bevorzuge ich es, immer LIMIT 1 innerhalb EXISTS.
LATERAL JOIN
SELECT
X.*
FROM
X
, LATERAL (
SELECT
Y.*
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
) Y
WHERE
Y IS DISTINCT FROM NULL;Diese Variante ermöglicht es auch, gleichzeitig einige Daten aus dem gefundenen verwandten Y-Eintrag zurĂŒckzugeben, falls erforderlich. Eine Ă€hnliche Variante wurde in dem Artikel behandelt .
âWarum mehr bezahlen?â: DISTINCT [ON] + LIMIT 1
Ein weiterer Vorteil solcher Abfrageumwandlungen ist die Möglichkeit, die Auswahl von DatensÀtzen leicht einzuschrÀnken, wenn nur einer oder mehrere davon benötigt werden, wie im folgenden Fall:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;Jetzt lesen wir die Abfrage und versuchen zu verstehen, was der DBMS vorgeschlagen wird:
- wir verbinden die Tabellen
- wir machen sie eindeutig nach X.pk
- aus den verbleibenden DatensÀtzen wÀhlen wir einen aus
Was haben wir also erhalten? âIrgendeinen Datensatzâ aus den einzigartigen â und wenn wir diesen einen aus den nicht eindeutigen nehmen, Ă€ndert sich das Ergebnis irgendwie? âWenn es keinen Unterschied gibt, warum mehr bezahlen?â
SELECT
*
FROM
(
SELECT
*
FROM
X
-- hier können passende Bedingungen eingefĂŒgt werden
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Das gleiche Thema gilt fĂŒr GROUP BY + LIMIT 1.
âIch muss nur fragenâ: implizite GROUP + LIMIT
Ăhnliche Dinge treten bei verschiedenen ĂberprĂŒfungen der Nicht-Leerheit von Tabellen oder CTE wĂ€hrend der AusfĂŒhrung der Abfrage auf:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ... Aggregatfunktionen (count/min/max/sum/...) funktionieren erfolgreich auf dem gesamten Satz, sogar ohne ausdrĂŒckliche Angabe GROUP BY. Nur das mit LIMIT sind sie nicht sehr kompatibel.
Der Entwickler könnte denken Wenn es dort EintrĂ€ge gibt, brauche ich nicht mehr als LIMIT. Aber das muss nicht sein! Denn fĂŒr die Datenbank ist das:
- Berechne, was gewĂŒnscht ist fĂŒr alle EintrĂ€ge
- Gib so viele Zeilen zurĂŒck, wie angefragt
Je nach den Zielbedingungen ist hier eine der Ersetzungen angebracht:
(count + LIMIT 1) = 0findet manNOT EXISTS(LIMIT 1)(count + LIMIT 1) > 0findet manEXISTS(LIMIT 1)count >= Nfindet man(SELECT count(*) FROM (... LIMIT N))
âWie viel in Gramm wiegt manâ: DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1Ein naiver Entwickler könnte fĂ€lschlicherweise annehmen, dass die AusfĂŒhrung der Anfrage stoppt, sobald wir die ersten $1 unterschiedlichen Werte gefunden haben.
In der Zukunft könnte das so funktionieren, dank eines neuen Knotens Index Skip Scan, dessen Implementierung derzeit erarbeitet wird, aber bisher â noch nicht.
ZunĂ€chst werden alle EintrĂ€ge extrahiert, einzigartig gemacht, und nur daraus wird zurĂŒckgegeben, was angefordert wurde. Besonders traurig wird es, wenn wir etwas wie $1 = 4, aber in der Tabelle â Hunderttausende von EintrĂ€genâŠ
Um den Frust zu vermeiden, benutzen wir eine rekursive Abfrage :

Quelle: habr.com
