PostgreSQL Antipatterns: Nirxandina Şertê di SQL de

SQL ne C++, û ne JavaScript e. Ji ber vê yekê, hesabkirina vegotinên mentiqî bi rengek cûda pêk tê, û ev qet ne heman tişt e:

WHERE fncondX() AND fncondY()

= fncondX() && fncondY()

Di pêvajoya xweşbînkirina plana darvekirina pirsê ya PostgreSQL de dikare bi kêfî şert û mercên wekhev "ji nû ve saz bike"., hin ji wan ji bo tomarên takekesî nehesibînin, wan bi şert û mercên îndeksa serîlêdanê ve girêbidin... Bi kurtî, awayê herî hêsan ew e ku hûn texmîn bikin ku hûn nikare kontrol bike ew ê bi çi rêzê (û ew ê bi tevahî bêne hesibandin) wekhev şert û mercên.

Ji ber vê yekê, heke hûn hîn jî dixwazin pêşîniyê birêve bibin, hûn hewce ne ku wê ava bikin van şertan newekhev bikin bikaranîna şertan îfadeyan и operatorên.

PostgreSQL Antipatterns: Nirxandina Şertê di SQL de
Dane û xebata bi wan re bingeh in kompleksa meya VLSI, ji ber vê yekê ji bo me pir girîng e ku operasyonên li ser wan ne tenê rast, lê di heman demê de bi bandor jî bêne kirin. Werin em li mînakên taybetî binihêrin ku li wan deran di hesabkirina îfadeyan de xeletî çêdibin, û li ku derê hêjayî başkirina karîgeriya wan e.

#0: RTFM

Destpêkirin mînakek ji belgeyê:

Dema ku rêza nirxandinê girîng e, ew dikare bi karanîna çêkirinê were girtin CASE. Mînakî, ev rêyek e ku meriv di hevokê de ji dabeşbûna bi sifirê dûr bixe WHERE bêbawer:

SELECT ... WHERE x > 0 AND y/x > 1.5;

Vebijarka ewle:

SELECT ... WHERE CASE WHEN x > 0 THEN y/x > 1.5 ELSE false END;

Sêwirana bi vî rengî tê bikar anîn CASE îfadeyê ji optimîzasyonê diparêze, ji ber vê yekê divê tenê gava ku hewce be were bikar anîn.

# 1: rewşa teşqele

BEGIN
  IF cond(NEW.fld) AND EXISTS(SELECT ...) THEN
    ...
  END IF;
  RETURN NEW;
END;

Her tişt baş xuya dike, lê ... Kes soz nade ku veberhênanê SELECT ger şerta yekem derew be dê neyê înfaz kirin. Ka em bi wê re rast bikin hêlîn kirin IF:

BEGIN
  IF cond(NEW.fld) THEN
    IF EXISTS(SELECT ...) THEN
      ...
    END IF;
  END IF;
  RETURN NEW;
END;

Naha em bi baldarî lê binihêrin - tevahiya laşê fonksiyona tetikê tê de "pêça" ye IF. Ev tê vê wateyê ku tiştek me nahêle ku em vê rewşê ji prosedurê bikar bînin WHEN- şert û mercên:

BEGIN
  IF EXISTS(SELECT ...) THEN
    ...
  END IF;
  RETURN NEW;
END;
...
CREATE TRIGGER ...
  WHEN cond(NEW.fld);

Ev nêzîkatî garantî ye ku çavkaniyên serverê dema ku şert derewîn xilas bike.

#2: AN / Û zincîra

SELECT ... WHERE EXISTS(... A) OR EXISTS(... B)

Wekî din, hûn dikarin bi herduyan re biqedin EXISTS dê "rast" be, lê herdu jî dê pêk bên.

Lê heke em bi rastî zanibin ku yek ji wan pir caran "rast" e (an "derew" - ji bo AND-zincîran) - gelo gengaz e ku meriv bi rengekî "pêşengiya xwe zêde bike" da ku ya duyemîn careke din neyê darve kirin?

Derket holê ku ew gengaz e - nêzîkatiya algorîtmîkî nêzî mijara gotarê ye PostgreSQL Antipatterns: tomarek kêm kêm dê bigihîje nîvê JOIN.

Werin em tenê van her du şertan di bin CASE de "bixin":

SELECT ...
WHERE
  CASE
    WHEN EXISTS(... A) THEN TRUE
    WHEN EXISTS(... B) THEN TRUE
  END

Di vê mijarê de me diyar nekir ELSE-nirx, ango heke her du şert jî derew in CASE dê vegere NULL, ku tê şîrovekirin FALSE в WHERE- şert û mercên.

Ev mînak dikare bi awayên din were berhev kirin - li gorî çêj û reng:

SELECT ...
WHERE
  CASE
    WHEN NOT EXISTS(... A) THEN EXISTS(... B)
    ELSE TRUE
  END

#3: Merc çawa [ne] binivîse

Me du roj derbas kir ku sedemên operasyona "xerîb" a vê tetikê analîz bikin - em bibînin ka çima.

Kanî:

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 ...

Pirsgirêk #1: newekhevî rêzê li NULL nagire

Werin em bifikirin ku her tişt OLD-Meydana zeviyan hebû NULL. Wê çi bibe?

SELECT NULL <> 1 OR NULL <> 2;
-- NULL

Û ji aliyê şert û mercên xebatê NULL berdêl FALSE, wek ku li jor behs kir.

biryar: operator bikar bînin IS DISTINCT FROM ji ROW-operator, berhevkirina tevahiya tomaran bi yekcarî:

SELECT (NULL, NULL) IS DISTINCT FROM (1, 2);
-- TRUE

Pirsgirêk #2: pêkanînên cihêreng ên heman fonksiyonê

Ka em bidin ber hev:

NEW."Документ_" = (select '"Комплект"'::regclass::oid)
NEW."Документ_" = (select to_regclass('"ДокументПоЗарплате"')::oid)

Çima li vir veberhênana zêde heye? SELECT? Fonksiyonek to_regclass? Çima cuda ye?..

Ka em rast bikin:

NEW."Документ_" = '"Комплект"'::regclass::oid
NEW."Документ_" = '"ДокументПоЗарплате"'::regclass::oid

Pirsgirêk # 3: pêşîniya operasyonên boolê

Ka em çavkaniyê format bikin:

{... IS NULL} OR
{... Комплект} OR
{... ДокументПоЗарплате} AND
( {... неравенства} )

Oops... Bi rastî, derket holê ku heke yek ji her du şertên pêşîn rast be, hemî şert vediguhere TRUE, bêyî ku newekheviyan hesab bike. Û ev qet ne ya ku me dixwest.

Ka em rast bikin:

(
  {... IS NULL} OR
  {... Комплект} OR
  {... ДокументПоЗарплате}
) AND
( {... неравенства} )

Pirsgirêk #4 (biçûk): Ji bo yek zeviyê şert OR tevlihev

Bi rastî, di jimare 3 de pirsgirêkên me hebûn tam ji ber ku sê şert hebûn. Lê li şûna wan, hûn dikarin bi yek mekanîzmayê bi dest bixin coalesce ... IN:

coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"')

Ji ber vê yekê em NULL "Em ê bigirin", û dijwar OR Ne hewce ye ku bi kemberan were dorpêç kirin.

Tevahî

Ka em tiştên ku me bi dest xistine tomar bikin:

IF (
  coalesce(NEW."Документ_"::text, '') IN ('', '"Комплект"', '"ДокументПоЗарплате"') AND
  (
    OLD."ДокументНашаОрганизация"
  , OLD."Удален"
  , OLD."Дата"
  , OLD."Время"
  , OLD."ЛицоСоздал"
  ) IS DISTINCT FROM (
    NEW."ДокументНашаОрганизация"
  , NEW."Удален"
  , NEW."Дата"
  , NEW."Время"
  , NEW."ЛицоСоздал"
  )
) THEN ...

Û heke hûn difikirin ku ev fonksiyona tetikê tenê dikare tê de were bikar anîn UPDATE-tetikîne ji ber hebûna OLD/NEW di rewşa asta jorîn de, wê hingê ev rewş bi gelemperî dikare were danîn WHEN- şert, wekî ku di #1 de tê xuyang kirin ...

Source: www.habr.com

Add a comment