SQL nuk është C++, as nuk është JavaScript. Prandaj, vlerësimi i shprehjeve logjike është i ndryshëm, dhe kjo nuk është aspak e njëjta gjë:
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
Ndërsa optimizoni planin e ekzekutimit të një pyetjeje PostgreSQL
Prandaj, nëse ende dëshironi të menaxhoni prioritetin, duhet ta menaxhoni në mënyrë strukturore i bëjnë këto kushte të pabarabarta me kusht
Të dhënat dhe puna me to është baza
#0: RTFM
Duke filluar
Kur rendi i vlerësimit është i rëndësishëm, ai mund të rregullohet me konstrukt
CASE
. Për shembull, në këtë mënyrë për të shmangur ndarjen me zero në një fjaliWHERE
e pabesueshme:SELECT ... WHERE x > 0 AND y/x > 1.5;
Opsioni i sigurt:
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Ndërtimi i përdorur
CASE
mbron shprehjen nga optimizimi, kështu që duhet të përdoret vetëm kur është e nevojshme.
# 1: gjendja e nxitjes
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Gjithçka duket se duket mirë, por... Askush nuk e premton se investimi SELECT
nuk do të ekzekutohet nëse kushti i parë është i rremë. Rregullojeni me folezuar IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Tani le të shohim me kujdes - i gjithë trupi i funksionit të këmbëzës doli të jetë "mbështjellë" brenda IF
. Dhe kjo do të thotë se asgjë nuk na pengon ta heqim këtë gjendje nga procedura e përdorimit WHEN
-kushtet
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Kjo qasje ju lejon të kurseni burimet e serverit me një garanci nëse kushti është i rremë.
#2: OSE/DHE zinxhir
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Përndryshe, mund të merret që të dyja EXISTS
do të jetë e vërtetë, por të dy do të ekzekutohen.
Por nëse e dimë me siguri se njëra prej tyre është "e vërtetë" shumë më shpesh (ose "e rreme" - për AND
-zinxhirët) - a është e mundur që disi të "rrisni përparësinë e tij" në mënyrë që i dyti të mos ekzekutohet edhe një herë?
Rezulton se është e mundur - qasja algoritmike është afër temës së artikullit
Le të "fusim nën CASE" të dyja këto kushte:
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Në këtë rast, ne nuk kemi përcaktuar ELSE
-vlera, domethënë nëse të dy kushtet janë false CASE
do te kthehen NULL
, e cila interpretohet si FALSE
в WHERE
- kushtet.
Ky shembull mund të kombinohet në një mënyrë tjetër - për shije dhe ngjyrë:
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3: si të [mos] shkruani kushtet
Ne kaluam dy ditë për të analizuar arsyet e ndezjes "të çuditshme" të këtij shkaktari - le të shohim pse.
Burimi:
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 ...
Problemi #1: Pabarazia nuk llogaritet për NULL
Le të supozojmë se gjithçka OLD
-Fushat kishin rëndësi NULL
. Çfarë do të ndodhë?
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Dhe nga pikëpamja e përpunimit të kushteve NULL
ekuivalente FALSE
, siç u përmend më lart.
vendim: përdorni operatorin IS DISTINCT FROM
ROW
-operator, duke krahasuar të gjitha të dhënat menjëherë:
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Problemi numër 2: zbatim i ndryshëm i të njëjtit funksionalitet
Le të krahasojmë:
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
Pse ka investime shtesë SELECT
? Një funksion to_regclass
? Pse eshte ndryshe...
Le të rregullojmë:
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
Problemi #3: përparësia bool
Le të formatojmë burimin:
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
Oops ... Në fakt, rezultoi se në rastin e vërtetësisë së ndonjë prej dy kushteve të para, e gjithë kushti kthehet në TRUE
, duke mos marrë parasysh pabarazitë. Dhe kjo nuk është aspak ajo që ne donim.
Le të rregullojmë:
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
Problemi #4 (i vogël): kusht kompleks OSE për një fushë
Në fakt ne kishim probleme në numrin 3 pikërisht sepse ishin tre kushte. Por në vend të tyre, ju mund të kaloni me një, duke përdorur mekanizmin coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
Kështu jemi edhe ne NULL
"kapur", dhe komplekse OR
Ju nuk duhet të shqetësoheni me kllapa.
Në total
Le të rregullojmë atë që kemi:
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
Dhe duke pasur parasysh se ky funksion aktivizues mund të përdoret vetëm në UPDATE
shkas për shkak të pranisë OLD/NEW
në gjendjen e nivelit të lartë, atëherë kjo gjendje në përgjithësi mund të hiqet WHEN
-gjendja siç tregohet në #1...
Burimi: www.habr.com