I SQL beskriver du "vad" du vill ha, inte "hur" det ska utföras. DÀrför ligger problemet med att utveckla SQL-frÄgor i stilen "som hörs, sÄ skrivs" pÄ sin hedersplats, jÀmte .
I dag kommer vi att titta pÄ nÄgra mycket enkla exempel pÄ vad detta kan leda till i sammanhanget av att anvÀnda GROUP/DISTINCT och LIMIT tillsammans med dem.
Om du har skrivit i frĂ„gan «först anslut dessa tabeller, och sedan ta bort alla dubbletter, det ska bara finnas en instans per nyckel» â sĂ„ kommer det att fungera, Ă€ven om anslutningen inte alls var nödvĂ€ndig.
Och ibland har man tur och det "bara fungerar", ibland pÄverkar det prestandan negativt, och ibland ger det helt ovÀntade effekter ur utvecklarens synvinkel.

NÄvÀl, kanske inte sÄ spektakulÀra, men...
«Söta paret»: JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition; Det Ă€r tydligt vad man ville vĂ€lj sĂ„dana poster X för vilka det finns kopplade poster i Y med det aktuella villkoret.FrĂ„gan skrevs genom JOIN â och man fick nĂ„gra pk-vĂ€rden flera gĂ„nger (exakt sĂ„ mĂ„nga som det fanns passande poster i Y). Hur tar man bort dem? SjĂ€lvklart DISTINCT!
Det Àr sÀrskilt "uppmuntrande" nÀr varje X-post hittar flera hundra kopplade Y-poster, och sedan tar man heroiskt bort dubbletterna...

Hur rĂ€ttar man till det? Först och frĂ€mst mĂ„ste man inse att uppgiften kan modifieras till «vĂ€lj sĂ„dana poster X för vilka det finns Ă
TMINSTONE ETT kopplad med det aktuella villkoret i Y» â för frĂ„n sjĂ€lva Y-posten behöver vi inget.
NĂ€stlad EXISTS
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
); Vissa versioner av PostgreSQL förstÄr att det i EXISTS Àr tillrÀckligt att hitta den första posten, Àldre versioner gör inte det. DÀrför föredrar jag alltid att ange LIMIT 1 inuti 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;Denna variant tillÄter ocksÄ att samtidigt returnera vissa data frÄn den funna kopplade Y-posten. En liknande variant har diskuterats i artikeln .
«Varför betala mer»: DISTINCT [ON] + LIMIT 1
En ytterligare fördel med denna typ av frÄgestÀllningar Àr möjligheten att enkelt begrÀnsa antalet poster, om endast en eller nÄgra av dem behövs, som i följande fall:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;Nu lÀser vi frÄgan och försöker förstÄ vad databashanteringssystemet föreslÄr att göra:
- vi kopplar samman tabellerna
- vi unikgör efter X.pk
- frÄn de ÄterstÄende posterna vÀljer vi nÄgon en
SĂ„ vad har vi fĂ„tt? «NĂ„gon enskild post» frĂ„n de unikifierade â och om vi tar denna enskilda frĂ„n de icke-unikifierade, skulle resultatet Ă€ndras pĂ„ nĂ„got sĂ€tt?.. «Och om det inte spelar nĂ„gon roll, varför betala mer?»
SELECT
*
FROM
(
SELECT
*
FROM
X
-- hÀr kan lÀmpliga villkor lÀggas till
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Och exakt samma tema med GROUP BY + LIMIT 1.
«Jag vill bara frÄga»: implicit GROUP + LIMIT
SÄdana saker förekommer vid olika kontroller av tomhet tabellen eller CTE under körningen av frÄgan:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ... Aggregatfunktioner (count/min/max/sum/...) kÀrnverkar över hela datasetet, Àven utan tydlig specifikation GROUP BY. Men de fungerar inte sÄ bra med LIMIT de.
Utvecklaren kan tÀnka «Om det finns poster dÀr, behöver jag inte mer Àn LIMIT». Men sÄ bör man inte tÀnka! Eftersom det för databasen Àr:
- berÀkna vad som efterfrÄgas ge tillbaka sÄ mÄnga rader som begÀrs
- Beroende pÄ mÄlvillkoren kan det vara lÀmpligt att göra en av följande byten:
(count + LIMIT 1) = 0
NOT EXISTS(LIMIT 1)till(count + LIMIT 1) > 0EXISTS(LIMIT 1)tillcount >= N(SELECT count(*) FROM (... LIMIT N))till«Hur mycket ska jag ta i gram»: DISTINCT + LIMIT
SELECT DISTINCT pk FROM X LIMIT $1
Den naiva utvecklaren kan uppriktigt tro att frÄgutvÀrderingen kommer att stoppas,sÄ fort vi hittar $1 första bÀsta olika vÀrden I framtiden kan det sÄ smÄningom fungera tack vare en ny nod.
Index Skip Scan , vars implementering just nu utarbetas, men Ă€n sĂ„ lĂ€nge â nej.För nu kommer först
alla poster att hÀmtas , unikgörs, och först frÄn dem kommer sÄ mÄnga som begÀrs att returneras. SÀrskilt sorgligt kan det bli om vi ville ha nÄgot som, men det finns hundratusentals poster i tabellen⊠$1 = 4För att inte grÄta i onödan, lÄt oss anvÀnda en rekursiv frÄga
«DISTINCT för fattiga» frÄn PostgreSQL Wiki :

KĂ€lla: habr.com
