Në SQL përshkruani «çfarë» dëshironi të merrni, jo «si» duhet të ekzekutohet. Pra, problemi i zhvillimit të pyetjeve SQL në stilin «si shprehet, ashtu dhe shkruhet» zë vendin e tij të nderuar, përkrah .
Sot do të shohim shembuj shumë të thjeshtë për atë çfarë mund të sjellë në kontekstin e përdorimit të GROUP/DISTINCT dhe LIMIT ndërsa bashkë me ta.
Ja, nĂ«se keni shkruar nĂ« pyetje «sĂ« pari bashkoni kĂ«to tabela, pastaj hiqni tĂ« gjitha kopjet, duhet tĂ« mbetet vetĂ«m njĂ« ekzemplar pĂ«r çdo çelĂ«s» â ashtu do tĂ« funksionojĂ«, edhe nĂ«se bashkimi nuk ka qenĂ« i nevojshĂ«m fare.
Dhe ndonjĂ«herĂ« ndodh qĂ« thjesht «punon», ndonjĂ«herĂ« â ndikon negativisht nĂ« performancĂ«, e ndonjĂ«herĂ« sjell efekte krejtĂ«sisht tĂ« papritura nga pikĂ«pamja e zhvilluesit.

Epo, ndoshta jo aq teatrale, porâŠ
«Ăifti i Ă«mbĂ«l»: JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition; Sa e qartĂ« Ă«shtĂ« se donit tĂ« zgjidhni kĂ«to regjistrime X, pĂ«r tĂ« cilat nĂ« Y ka lidhje me kushtin qĂ« po ekzekutohet. E shkruajtĂ«t pyetjen pĂ«rmes JOIN â morĂ«m disa vlera pk disa herĂ« (saktĂ«sisht sa shumĂ« regjistra tĂ« pĂ«rshtatshĂ«m nĂ« Y rezultuan). Si ta eliminojmĂ«? Sigurisht DISTINCT!
Sidomos âgĂ«zonâ kur pĂ«r çdo regjistĂ«r X gjenden disa qindra regjistra tĂ« lidhur Y, dhe mĂ« pas heroikisht hiqen dublikatet...

Si ta rregullojmĂ«? SĂ« pari, tĂ« kuptojmĂ« se detyra mund tĂ« modifikohet nĂ« âtĂ« pĂ«rzgjidhen regjistrat X, pĂ«r tĂ« cilat nĂ« Y ka TĂ PAKTĂN NJĂ regjistĂ«r tĂ« lidhur me kushtin e ekzekutimitâ â sepse nga regjistri Y vetĂ« nuk na nevojitet asgjĂ«.
Nënshkrimi EXISTS
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
); Disa versione tĂ« PostgreSQL kuptojnĂ« se nĂ« EXISTS mjafton tĂ« gjendet regjistri i parĂ« qĂ« kapet, versionet mĂ« tĂ« vjetra â jo. Prandaj preferoj gjithmonĂ« tĂ« tregoj LIMIT 1 brenda 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;Ky variant gjithashtu lejon, nëse është e nevojshme, të kthehen menjëherë disa të dhëna nga regjistri i lidhur Y që u gjet. Një variant i ngjashëm është shqyrtuar në artikullin .
âPse tĂ« paguani mĂ« shumĂ«â: DISTINCT [ON] + LIMIT 1
Një avantazh shtesë i këtij lloji të transformimeve të pyetjeve është mundësia për të kufizuar lehtësisht ciklin e regjistrimeve, nëse nevojitet vetëm një/disa prej tyre, si në rastin në vijim:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;Tani lexohet pyetja dhe përpiqemi të kuptojmë se çfarë propozohet të bëjë DBMS:
- kemi lidhur tabelat
- e bëjmë unike sipas X.pk
- nga regjistrimet e mbetura zgjedhim ndonjë një
Pra, çfarë kemi marrë? «Një regjistrim ndonjë» nga të unifikuar - po sikur ta marrim këtë një nga të paunifikuarit, rezultatet do të ndryshonin ndonjëherë?.. «Po nëse nuk ka ndonjë ndryshim, pse të paguajmë më shumë?»
SELECT
*
FROM
(
SELECT
*
FROM
X
-- këtu mund të futni kushte të përshtatshme
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Dhe i njëjti qëndrim me GROUP BY + LIMIT 1.
«Më mjafton të pyes»: GROUP i implicit + LIMIT
Këto gjëra hasen në raste të ndryshme kontrollesh për mosrënien bosh tabelash ose CTE gjatë ekzekutimit të pyetjes:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ... Funksionet agregate (count/min/max/sum/...) ekzekutohen me sukses në të gjithë grupin, madje edhe pa specifikimin e qartë GROUP BY. Por ata me LIMIT nuk shkojnë shumë mirë.
Programuesi mund të mendojë «Nëse ka regjistrime atje, atëherë nuk më duhet më shumë se LIMIT». Por mos e bën këtë! Sepse për bazën kjo është:
- llogarita se çfarë dëshirojnë për të gjitha regjistrimet
- kthe sa rreshta kërkohet
Varësisht nga kushtet e synuara, këtu është i përshtatshëm një nga zëvendësimet:
(count + LIMIT 1) = 0nëNOT EXISTS(LIMIT 1)(count + LIMIT 1) > 0nëEXISTS(LIMIT 1)count >= Nnë(SELECT count(*) FROM (... LIMIT N))
«Sa të peshojë në gramë»: DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1Një zhvillues naiv mund të mendojë sinqerisht se ekzekutimi i pyetjes do të ndalet sapohesht të gjejmë $1 të parë të ndryshme vlera.
Ndoshta nĂ« tĂ« ardhmen kjo do tĂ« funksionojĂ« falĂ« njĂ« node tĂ« re Index Skip Scan, realizimi i sĂ« cilĂ«s aktualisht po punohet, por pĂ«r momentin â jo.
Për momentin, së pari do të nxirren të gjitha regjistrimet, unikizohen, dhe vetëm nga ato do të kthehet sa kërkohet. Sidomos është e trishtueshme nëse ne dëshirojmë diçka si $1 = 4, ndërsa regjistrimet në tabelë janë qindra mijë...
Për të mos u ndjerë keq kot, le të përdorim një kërkesë rekurzive :

Burimi: habr.com
