In SQL, you describe "what" you want to obtain, not "how" it should be executed. Thus, the problem of developing SQL queries in a "write as you hear it" style holds a worthy place, alongside .
Today, through extremely simple examples, we will look at where that can lead in the context of using GROUP/DISTINCT und LIMIT alongside them.
If you wrote in the query "first join these tables, and then remove all duplicates, only one instance per key should remain" â thatâs exactly how it will work, even if the join wasnât necessary at all.
And sometimes it just works, sometimes it negatively affects performance, and sometimes it produces completely unexpected results from the developer's point of view.

Well, maybe not as spectacular, butâŠ
"Sweet couple": JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition; Itâs clear that they wanted to select such records X for which there are related records in Y that meet the executing condition.They wrote a query through JOIN â and got some pk values multiple times (exactly as many as suitable records were in Y). How to eliminate this? Of course, DISTINCT!
Itâs especially "delightful" when for each X record hundreds of related Y records are found, and then duplicates are heroically removedâŠ

How to fix this? First, realize that the task can be modified to "select those records X for which there is AT LEAST ONE related record in Y that meets the executing condition" â since we donât need anything from the Y record itself.
Nested EXISTS
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
); Some versions of PostgreSQL understand that it's enough to find the first matching record for EXISTS; older versions do not. Therefore, I prefer to always specify 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;This option allows you to also immediately return some data from the found related Y record if necessary. A similar option is discussed in the article .
"Why Pay More": DISTINCT [ON] + LIMIT 1
Ein weiterer Vorteil solcher Anfrageumwandlungen ist die Möglichkeit, die Ergebnismenge leicht einzuschrÀnken, falls nur eine 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 die Datenbankmanagementsystem (DBMS) machen soll:
- wir verbinden die Tabellen
- wir machen sie eindeutig nach X.pk
- aus den verbleibenden DatensÀtzen wÀhlen wir irgendeinen aus
Was haben wir also? âIrgendeinen Datensatzâ aus den eindeutigen â und wenn wir diesen einen aus den nicht eindeutigen nehmen, Ă€ndert sich das Ergebnis dann nicht irgendetwas?.. âUnd 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;
Und das gleiche Thema mit GROUP BY + LIMIT 1.
âIch muss nur fragenâ: implizite GROUP + LIMIT
Solche Dinge begegnen bei verschiedenen ĂberprĂŒfungen auf Nichtigkeit Tabellen oder CTE wĂ€hrend der AusfĂŒhrung der Abfrage:
...
CASE
WHEN (
SELECT
count(*))
FROM
X
LIMIT 1
) = 0 THEN ... Aggregatfunktionen (count/min/max/sum/...) funktionieren erfolgreich auf dem gesamten Datensatz, selbst ohne explizite Angabe GROUP BY. Nur mit LIMIT verstehen sie sich nicht sehr gut.
Der Entwickler könnte denken âWenn dort DatensĂ€tze vorhanden sind, dann brauche ich nicht mehr als das LIMITâ. Aber so sollte es nicht sein! Denn fĂŒr die Datenbank bedeutet das:
- zĂ€hl, was gewĂŒnscht ist gib so viele Zeilen zurĂŒck, wie verlangt
- Je nach Zielbedingungen ist es hier sinnvoll, eine der folgenden Ersetzungen vorzunehmen:
(count + LIMIT 1) = 0
NOT EXISTS(LIMIT 1)auf(count + LIMIT 1) > 0EXISTS(LIMIT 1)aufcount >= N(SELECT count(*) FROM (... LIMIT N))aufâWie viel in Gramm wiegenâ: DISTINCT + LIMIT
SELECT DISTINCT pk FROM X LIMIT $1
Ein naiver Entwickler könnte aufrichtig glauben, dass die AusfĂŒhrung der Abfrage Stoppen wird,sobald wir die ersten $1 verschiedenen Werte gefunden haben In der Zukunft könnte das so funktionieren Dank eines neuen Knotens.
Index Skip Scan , dessen Implementierung derzeit ausgearbeitet wird, aber bisher â nein.Bis jetzt werden zuerst
alle DatensĂ€tze extrahiert , einzigartig gemacht, und nur dann wird zurĂŒckgegeben, was angefordert wurde. Besonders traurig ist es, wenn wir etwas wollten wie, und in der Tabelle sind es Hunderttausende⊠$1 = 4Um unnötige Traurigkeit zu vermeiden, nutzen wir die rekursive Abfrage
âDISTINCT fĂŒr Armeâ aus dem PostgreSQL Wiki :

Quelle: habr.com
