SQL-is kirjeldad, mida sa soovid saada, mitte kuidas see peaks toimuma. SeetÔttu on SQL-pÀringute arendamise probleem, mis on stiilis "kuidas see kÔlab, nii see kirjutatakse", oma auvÀÀrsel kohal, koos .
TÀna vaatame ÀÀrmiselt lihtsate nÀidete kaudu, millele see vÔib viia kontekstis, kus kasutatakse GROUP/DISTINCT ja LIMIT koos nendega.
Kui olete pĂ€ringus kirjutanud "esmalt ĂŒhenda need tabelid ja seejĂ€rel eemalda kĂ”ik dubleerimised, peab jÀÀma vaid ĂŒks nĂ€ide iga vĂ”tme kohta" â just nii see ka töötab, isegi kui liitmine polnud ĂŒldse vajalik.
Ja mÔnikord juhtub, et see "lihtsalt töötab", mÔnikord avaldab see negatiivset mÔju jÔudlusele ja mÔnikord annab tÀiesti ootamatuid efekte arendaja vaatepunktist.

Noh, vĂ”ib-olla mitte nii muljetavaldavad, kuidâŠ
"Magus paar": JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition; On arusaadav, et sooviti valida sellised X-kirjed, mille jaoks Y-s on seotud olemasoleva tingimusega. Kirjutati pĂ€ring lĂ€bi JOIN â saadi mĂ”ned pk vÀÀrtused mitu korda (just nii palju, kui leidus sobivaid kirjeid Y-s). Kuidas eemaldada? Muidugi STDEV!
Eriti "rÔÔmustav" on see, kui iga X-kirje kohta leitakse sadu seotud Y-kirjeid ja siis kangelaslikult eemaldatakse dubleerimisedâŠ

Kuidas parandada? Esiteks tuleb mĂ”ista, et ĂŒlesannet saab muuta kuju "valida sellised X-kirjed, mille jaoks Y-s on KASVĂ”i ĂKS seotud olemasoleva tingimusega" â sest kuskilt Y-kirjest me ei vaja midagi.
Sisemine EXISTS
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
); MÔned PostgreSQL versioonid mÔistavad, et EXISTS piisab, kui leida esimene leitud kirje, vanemad versioonid ei mÔista. SeetÔttu eelistan alati mÀrkida LIMIT 1 sees 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;See variant vÔimaldab vajadusel koheselt tagastada ka andmed leitud seotud Y-kirjest. Sarnast varianti kÀsitletakse artiklis .
"Miks maksta rohkem": DISTINCT [ON] + LIMIT 1
LisavÀÀrtuseks antud pĂ€ringute muutmise puhul on vĂ”imalus hĂ”lpsasti piirata kirjeid, kui vaja on ainult ĂŒks/mitu neist, nagu allpool nĂ€idatud:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;NĂŒĂŒd loeme pĂ€ringut ja ĂŒritame aru saada, mida andmebaasipĂŒstitus ette nĂ€eb:
- ĂŒhendame tabelid
- teeme unikaalseks X.pk jÀrgi
- jĂ€tkuvatest kirjetest valime mingi ĂŒhe
Kuidas me seda saime? âMingi ĂŒks kirjeâ unikaalsetest â aga kui vĂ”tta see ĂŒks mitteunikaalsete seast, kas tulemus muutub? .. âKui pole vahet, miks maksta rohkem?â
SELECT
*
FROM
(
SELECT
*
FROM
X
-- siia vÔib panna sobivaid tingimusi
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Ja tÀpselt sama teema on GROUP BY + LIMIT 1.
âMa vĂ”in lihtsalt kĂŒsidaâ: vaikne GROUP + LIMIT
Sellised asjad esinevad erinevate tĂŒhjuse kontrollide tabeli vĂ”i CTE kĂ€igus pĂ€ringu tĂ€itmisel:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ... Agregaatfunktsioonid (count/min/max/sum/...) tÀidetakse edukalt kogu komplektile, isegi ilma selge mÀÀramiseta on olemas, vaate mÀÀratlemine peab sisaldama. Ainult et LIMIT nad ei sobi hÀsti.
Arendaja vĂ”ib mĂ”elda âkui seal on kirjed, siis mul pole vaja rohkem LIMIT-iâ. Kuid seda ei tohi teha! Sest andmebaasile see tĂ€hendab:
- loenda, mida soovitakse anna tagasi nii palju ridu, kui palutakse
- Olenevalt sihttingimustest on siin sobilik teha ĂŒks asendus:
(count + LIMIT 1) = 0
NOT EXISTS(LIMIT 1). Tundub, et(count + LIMIT 1) > 0EXISTS(LIMIT 1). Tundub, etcount >= N(SELECT count(*) FROM (... LIMIT N)). Tundub, etâKui palju grammidesse pannaâ: DISTINCT + LIMIT
SELECT DISTINCT pk FROM X LIMIT $1
Naivne arendaja vÔib siiralt arvata, et pÀringu tÀitmine lÔpetatakse,niipea, kui leiame $1 esimesest ettejuhtuvast erinevast vÀÀrtusest Kusagil tulevikus vÔib see tÔesti nii toimida uue sÔlme.
Index Skip Scan , mille rakendust töötatakse praegu vĂ€lja, kuid praegu â ei.Praegu tĂ”mmatakse kĂ”igepealt kĂ”ik kirjed
, unikaalsed ja juba neist tagastatakse nii palju, kui on nĂ”utud. Eriti kurb on see, kui soovisime midagi sellist , kuid tabelis on sadu tuhandeidâŠEt mitte asjatult kurvastada, kasutame rekuurse pĂ€ringut $1 = 4âDISTINCT vaesteleâ PostgreSQL Wiki-st
SQL-is kirjeldad, mida soovid saada, mitte kuidas seda tÀidetakse. :

Allikas: habr.com
