SQL C++ emas, JavaScript ham emas. Shuning uchun mantiqiy ifodalarni baholash boshqacha va bu umuman bir xil emas:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
PostgreSQL so'rovini bajarish rejasini optimallashtirishda
Shuning uchun, agar siz hali ham ustuvorlikni boshqarishni istasangiz, tizimli ravishda qilishingiz kerak bu shartlarni tengsiz qiling shartli bilan
Ma'lumotlar va ular bilan ishlash asosdir
β 0: RTFM
Boshlanmoqda
Baholash tartibi muhim bo'lsa, uni konstruktsiya bilan tuzatish mumkin
CASE
. Masalan, jumlada nolga bo'linmaslikning bu usuliWHERE
ishonchsiz:SELECT ... WHERE x > 0 AND y/x > 1.5;
Xavfsiz variant:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Amaldagi qurilish
CASE
ifodani optimallashtirishdan himoya qiladi, shuning uchun uni faqat kerak bo'lganda ishlatish kerak.
β1: ishga tushirish holati
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Hamma narsa yaxshi ko'rinadi, lekin ... Hech kim investitsiya qilinganini va'da qilmaydi SELECT
birinchi shart noto'g'ri bo'lsa, bajarilmaydi. bilan tuzating o'rnatilgan IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Endi diqqat bilan qaraylik - tetik funktsiyasining butun tanasi "o'ralgan" bo'lib chiqdi IF
. Va bu shuni anglatadiki, bizni ushbu holatni foydalanish tartibidan olib tashlashga hech narsa to'sqinlik qilmaydi WHEN
- shartlar
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Ushbu yondashuv, agar shart noto'g'ri bo'lsa, server resurslarini kafolat bilan saqlashga imkon beradi.
β2: YOKI/VA zanjiri
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Aks holda, ikkalasini ham olish mumkin EXISTS
to'g'ri bo'ladi, lekin ikkalasi ham bajariladi.
Ammo agar biz ulardan biri "to'g'ri" ekanligini aniq bilsak, tez-tez (yoki "noto'g'ri" - uchun AND
-zanjirlar) - ikkinchisi yana bir bor bajarilmasligi uchun qandaydir tarzda "uning ustuvorligini oshirish" mumkinmi?
Ma'lum bo'lishicha, bu mumkin - algoritmik yondashuv maqola mavzusiga yaqin
Keling, ikkala shartni ham "CASE ostida turaylik":
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Bu holatda biz aniqlamadik ELSE
-qiymat, ya'ni ikkala shart ham noto'g'ri bo'lsa CASE
qaytadi NULL
, deb talqin etiladi FALSE
Π² WHERE
- sharoitlar.
Ushbu misolni boshqa yo'l bilan birlashtirish mumkin - ta'mga va rangga:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
β3: shartlarni qanday yozmaslik kerak
Biz ikki kun davomida ushbu qo'zg'atuvchining "g'alati" ishga tushishining sabablarini tahlil qildik - keling, nima uchun ekanligini bilib olaylik.
Manba:
IF( NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" is null or NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid) or NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select to_regclass('"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')::oid)
AND ( OLD."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ" <> NEW."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
OR OLD."Π£Π΄Π°Π»Π΅Π½" <> NEW."Π£Π΄Π°Π»Π΅Π½"
OR OLD."ΠΠ°ΡΠ°" <> NEW."ΠΠ°ΡΠ°"
OR OLD."ΠΡΠ΅ΠΌΡ" <> NEW."ΠΡΠ΅ΠΌΡ"
OR OLD."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»" <> NEW."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»" ) ) THEN ...
Muammo β1: Tengsizlik NULLni hisobga olmaydi
Faraz qilaylik, hamma narsa OLD
- maydonlar muhim edi NULL
. Nima bo'ladi?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Va shartlarni ishlab chiqish nuqtai nazaridan NULL
ekvivalent FALSE
, yuqorida aytib o'tilganidek.
qaror: operatordan foydalaning IS DISTINCT FROM
ROW
-operator, bir vaqtning o'zida butun yozuvlarni taqqoslash:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
2-muammo: bir xil funktsiyani turlicha amalga oshirish
Keling, solishtiring:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid)
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = (select to_regclass('"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')::oid)
Nima uchun qo'shimcha investitsiyalar mavjud SELECT
? Funktsiya to_regclass
? Nega boshqacha...
Keling, tuzatamiz:
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"'::regclass::oid
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_" = '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"'::regclass::oid
β3 muammo: bool ustunligi
Keling, manbani formatlaymiz:
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅} AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Voy ... Aslida, birinchi ikkita shartning birortasi haqiqatga to'g'ri kelgan taqdirda, butun shartga aylanadi. TRUE
, tengsizliklarni hisobga olmaganda. Va bu biz xohlagan narsa emas.
Keling, tuzatamiz:
(
{... IS NULL} OR
{... ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ} OR
{... ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅}
) AND
( {... Π½Π΅ΡΠ°Π²Π΅Π½ΡΡΠ²Π°} )
Muammo β4 (kichik): bitta maydon uchun murakkab YOKI shart
Aslida, 3-raqamda muammolarga duch keldik, chunki uchta shart bor edi. Ammo ularning o'rniga siz mexanizmdan foydalanib, bittasi bilan olishingiz mumkin coalesce ... IN
:
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"')
Biz ham shundaymiz NULL
"ushlash" va murakkab OR
Qavslar bilan ovora bo'lishingiz shart emas.
jami
Keling, nima borligini aniqlaymiz:
IF (
coalesce(NEW."ΠΠΎΠΊΡΠΌΠ΅Π½Ρ_"::text, '') IN ('', '"ΠΠΎΠΌΠΏΠ»Π΅ΠΊΡ"', '"ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠΎΠΠ°ΡΠΏΠ»Π°ΡΠ΅"') AND
(
OLD."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, OLD."Π£Π΄Π°Π»Π΅Π½"
, OLD."ΠΠ°ΡΠ°"
, OLD."ΠΡΠ΅ΠΌΡ"
, OLD."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
) IS DISTINCT FROM (
NEW."ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠΠ°ΡΠ°ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΡ"
, NEW."Π£Π΄Π°Π»Π΅Π½"
, NEW."ΠΠ°ΡΠ°"
, NEW."ΠΡΠ΅ΠΌΡ"
, NEW."ΠΠΈΡΠΎΠ‘ΠΎΠ·Π΄Π°Π»"
)
) THEN ...
Va bu trigger funktsiyasidan faqat foydalanish mumkinligini hisobga olsak UPDATE
mavjudligi sababli tetik OLD/NEW
yuqori darajadagi holatda, keyin bu holat odatda olib tashlanishi mumkin WHEN
-1-sonda ko'rsatilganidek, vaziyat ...
Manba: www.habr.com