ProHoster > Blog > İdarə > PostgreSQL Antipatternləri: "Yalnız bir olmalıdır!"
PostgreSQL Antipatternləri: "Yalnız bir olmalıdır!"
SQL-də siz "necə" yerinə yetirilməli olduğunu deyil, "nə" əldə etmək istədiyinizi təsvir edirsiniz. Buna görə də SQL sorğularının “eşitdiyi kimi yazılır” üslubunda işlənib hazırlanması problemi öz şərəfli yerini tutur. SQL-də şərtlərin hesablanması xüsusiyyətləri.
Bu gün, son dərəcə sadə nümunələrdən istifadə edərək, bunun istifadə kontekstində nəyə səbəb ola biləcəyinə baxaq GROUP/DISTINCT и LIMIT onlarla.
İndi sorğuda yazsanız "Əvvəlcə bu işarələri birləşdirin, sonra bütün dublikatları atın, yalnız biri qalmalıdır hər açar üçün kopyalayın" - əlaqə ümumiyyətlə lazım olmasa belə, tam olaraq belə işləyəcək.
Və bəzən şanslısınız və o, "sadəcə işləyir", bəzən performansa xoşagəlməz təsir göstərir, bəzən isə tərtibatçının nöqteyi-nəzərindən tamamilə gözlənilməz effektlər verir.
Yaxşı, bəlkə o qədər də möhtəşəm deyil, amma...
"Şirin cütlük": QOŞULUN + FƏRQLİ
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition;
Nə istədikləri bəlli olardı yerinə yetirilən şərtlə bağlı Y-də qeydlər olan X qeydlərini seçin. vasitəsilə sorğu yazdı JOIN - bir neçə dəfə bəzi pk dəyərləri əldə etdi (Y-də dəqiq neçə uyğun giriş var). Necə aradan qaldırmaq olar? Əlbəttə DISTINCT!
Hər bir X-rekord üçün bir neçə yüz əlaqəli Y-rekord olduğu və sonra dublikatların qəhrəmancasına silinməsi xüsusilə “sevindiricidir”...
Necə düzəltmək olar? Başlamaq üçün problemin dəyişdirilə biləcəyini anlayın “Y-də yerinə yetirilmiş şərtlə bağlı AZAL BİR olan X qeydlərini seçin” - Axı Y-rekordunun özündən heç nəyə ehtiyacımız yoxdur.
İç-içə VAR
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
);
PostgreSQL-in bəzi versiyaları başa düşür ki, EXISTS-də ortaya çıxan ilk girişi tapmaq kifayətdir, köhnələri isə yox. Ona görə də həmişə qeyd etməyi üstün tuturam LIMIT 1 daxilində EXISTS.
YANAL QOŞULUN
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;
“Niyə daha çox ödəməlisiniz”: DISTINCT [ON] + LIMIT 1
Bu cür sorğu çevrilmələrinin əlavə faydası aşağıdakı hallarda olduğu kimi onlardan yalnız bir və ya bir neçəsinə ehtiyac olduqda qeydlərin axtarışını asanlıqla məhdudlaşdırmaq imkanıdır:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
İndi sorğunu oxuyuruq və DBMS-nin nə etməyi təklif etdiyini anlamağa çalışırıq:
işarələri birləşdirir
X.pk tərəfindən unikal
qalan qeydlərdən birini seçin
Bəs siz nə əldə etdiniz? "Sadəcə bir giriş" unikal olanlardan - və əgər bu qeyri-adi olanlardan birini götürsək, nəticə birtəhər dəyişəcəkmi?.. “Və heç bir fərq yoxdursa, niyə daha çox pul ödəyəsiniz?”
SELECT
*
FROM
(
SELECT
*
FROM
X
-- сюда можно подсунуть подходящих условий
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
Və eyni mövzu ilə GROUP BY + LIMIT 1.
“Mən sadəcə xahiş etməliyəm”: gizli QRUP + LİMİT
Oxşar şeylər fərqli şəkildə baş verir boşluq olmayan çeklər sorğu irəlilədikcə işarələr və ya CTE-lər:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ...
Ümumi funksiyalar (count/min/max/sum/...) hətta açıq göstərişlər olmadan bütün dəstdə uğurla icra edilir GROUP BY. Yalnız ilə LIMIT çox mehriban deyillər.
Tərtibatçı düşünə bilər "Əgər orada qeydlər varsa, o zaman mənə LIMIT-dən çox ehtiyac yoxdur". Amma bunu etmə! Çünki baza üçün bu:
istədiklərini saysınlar bütün qeydlərə görə
istədikləri qədər sətir verin
Hədəf şərtlərindən asılı olaraq, aşağıdakı əvəzetmələrdən birini etmək məqsədəuyğundur:
(count + LIMIT 1) = 0haqqındaNOT EXISTS(LIMIT 1)
(count + LIMIT 1) > 0haqqındaEXISTS(LIMIT 1)
count >= Nhaqqında(SELECT count(*) FROM (... LIMIT N))
"Qramlarda nə qədər asmaq olar": DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1
Sadəlövh bir tərtibatçı sorğunun icrasını dayandıracağına səmimi şəkildə inana bilər. rastlaşdığımız ilk fərqli dəyərlərin 1 dollarını tapan kimi.
Gələcəkdə bu, yeni bir qovşaq sayəsində işləyə bilər və işləyəcək İndeks Skanını Atlayın, hazırda icrası üzərində iş gedir, lakin hələ yox.
Hələlik birinci bütün qeydlər alınacaq, unikaldır və yalnız onlardan tələb olunan məbləğ geri qaytarılacaq. Belə bir şey istəsək xüsusilə kədərlidir $ 1 = 4, və cədvəldə yüz minlərlə qeyd var...