SQL-ը C++ չէ, ոչ էլ JavaScript: Հետևաբար, տրամաբանական արտահայտությունների գնահատականը տարբեր է, և սա ամենևին էլ նույնը չէ.
WHERE fncondX() AND fncondY()
= fncondX() && fncondY()
PostgreSQL հարցման կատարման պլանը օպտիմալացնելիս
Հետևաբար, եթե դուք դեռ ցանկանում եք կառավարել առաջնահերթությունը, դուք պետք է կառուցվածքայինորեն կառավարեք դարձնել այս պայմանները անհավասար պայմանականով
Տվյալները և դրանց հետ աշխատելը հիմք են հանդիսանում
#0: RTFM
Սկսելով
Երբ գնահատման կարգը կարևոր է, այն կարելի է ամրագրել կոնստրուկտով
CASE
. Օրինակ, այս կերպ խուսափել նախադասության մեջ զրոյի բաժանումիցWHERE
անվստահելի:SELECT ... WHERE x > 0 AND y/x > 1.5;
Անվտանգ տարբերակ.
SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;
Օգտագործված շինարարությունը
CASE
պաշտպանում է արտահայտությունը օպտիմալացումից, ուստի այն պետք է օգտագործվի միայն անհրաժեշտության դեպքում:
# 1: ձգանման պայման
BEGIN
IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
Ամեն ինչ կարծես թե լավ է, բայց... Ոչ ոք չի խոստանում, որ ներդրվածը SELECT
չի կատարվի, եթե առաջին պայմանը կեղծ է: Ուղղեք այն բնադրված IF
:
BEGIN
IF cond(NEW.fld) THEN
IF EXISTS(SELECT ...) THEN
...
END IF;
END IF;
RETURN NEW;
END;
Հիմա եկեք ուշադիր նայենք, պարզվեց, որ ձգան գործառույթի ամբողջ մարմինը «փաթաթված» է IF
. Եվ սա նշանակում է, որ ոչինչ չի խանգարում մեզ այս պայմանը հեռացնել ընթացակարգից WHEN
-պայմաններ
BEGIN
IF EXISTS(SELECT ...) THEN
...
END IF;
RETURN NEW;
END;
...
CREATE TRIGGER ...
WHEN cond(NEW.fld);
Այս մոտեցումը թույլ է տալիս պահպանել սերվերի ռեսուրսները երաշխիքով, եթե պայմանը կեղծ է:
#2՝ ԿԱՄ/ԵՎ շղթա
SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)
Հակառակ դեպքում կարելի է ձեռք բերել, որ երկուսն էլ EXISTS
ճիշտ կլինի, բայց երկուսն էլ մահապատժի են ենթարկվելու.
Բայց եթե մենք հաստատ գիտենք, որ դրանցից մեկը շատ ավելի հաճախ է «ճշմարիտ» (կամ «կեղծ»՝ համար AND
-շղթաներ) - հնարավո՞ր է ինչ-որ կերպ «մեծացնել դրա առաջնահերթությունը», որպեսզի երկրորդը ևս մեկ անգամ չկատարվի:
Պարզվում է, որ դա հնարավոր է՝ ալգորիթմական մոտեցումը մոտ է հոդվածի թեմային
Եկեք ուղղակի «խցկենք CASE-ի տակ» այս երկու պայմաններից էլ.
SELECT ...
WHERE
CASE
WHEN EXISTS(... A) THEN TRUE
WHEN EXISTS(... B) THEN TRUE
END
Այս դեպքում մենք չենք սահմանել ELSE
-արժեք, այսինքն, եթե երկու պայմաններն էլ կեղծ են CASE
կվերադառնա NULL
, որը մեկնաբանվում է որպես FALSE
в WHERE
- պայմանները.
Այս օրինակը կարելի է համատեղել այլ կերպ՝ ըստ ճաշակի և գույնի.
SELECT ...
WHERE
CASE
WHEN NOT EXISTS(... A) THEN EXISTS(... B)
ELSE TRUE
END
#3. ինչպես [չ] գրել պայմաններ
Մենք երկու օր ծախսեցինք այս ձգանի «տարօրինակ» գործարկման պատճառների վերլուծության վրա. տեսնենք, թե ինչու:
Աղբյուր.
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 ...
Խնդիր թիվ 1. անհավասարությունը չի հաշվի առնում NULL-ը
Ենթադրենք, որ ամեն ինչ OLD
- դաշտերը կարևոր էին NULL
. Ի՞նչ է լինելու։
SELECT NULL <> 1 OR NULL <> 2;
-- NULL
Իսկ պայմանները մշակելու տեսանկյունից NULL
համարժեք FALSE
, ինչպես նշվեց վերևում:
որոշումՕգտագործեք օպերատոր IS DISTINCT FROM
ROW
- օպերատոր, ամբողջ գրառումները միանգամից համեմատելով.
SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE
Խնդիր թիվ 2. նույն ֆունկցիոնալության տարբեր իրականացում
Եկեք համեմատենք.
NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)
Ինչու են լրացուցիչ ներդրումներ SELECT
? Գործառույթ to_regclass
? Ինչու՞ է տարբեր...
Եկեք շտկենք.
NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid
Խնդիր թիվ 3. բուլ գերակայություն
Եկեք ձևաչափենք աղբյուրը.
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )
Օփ... Փաստորեն, պարզվեց, որ առաջին երկու պայմաններից որևէ մեկի ճշմարտացիության դեպքում ամբողջ պայմանը վերածվում է. TRUE
, անտեսելով անհավասարությունները։ Եվ սա ամենևին էլ այն չէ, ինչ մենք ուզում էինք։
Եկեք շտկենք.
(
{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате}
) AND
( {... неравенства} )
Խնդիր թիվ 4 (փոքր). բարդ ԿԱՄ պայման մեկ դաշտի համար
Փաստորեն, թիվ 3-ում խնդիրներ ունեինք հենց այն պատճառով, որ երեք պայման կար. Բայց դրանց փոխարեն դուք կարող եք յոլա գնալ մեկով՝ օգտագործելով մեխանիզմը coalesce ... IN
:
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')
Մենք նույնպես NULL
«բռնել», և բարդ OR
Պետք չէ իրարանցում անել փակագծերով:
Ընդհանուր
Եկեք շտկենք այն, ինչ ստացել ենք.
IF (
coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
(
OLD."ДокументНашаОрганизация"
, OLD."Удален"
, OLD."Дата"
, OLD."Время"
, OLD."ЛицоСоздал"
) IS DISTINCT FROM (
NEW."ДокументНашаОрганизация"
, NEW."Удален"
, NEW."Дата"
, NEW."Время"
, NEW."ЛицоСоздал"
)
) THEN ...
Եվ հաշվի առնելով, որ այս ձգան գործառույթը կարող է օգտագործվել միայն UPDATE
ձգան՝ առկայության պատճառով OLD/NEW
վերին մակարդակի վիճակում, ապա այս վիճակը կարող է ընդհանրապես դուրս հանվել WHEN
- վիճակ, ինչպես ցույց է տրված թիվ 1-ում...
Source: www.habr.com