Antipatterns PostgreSQL: measadh suidheachadh ann an SQL

Chan e C ++ a th’ ann an SQL, agus chan e JavaScript. Mar sin, tha àireamhachadh abairtean loidsigeach a 'tachairt ann an dòigh eadar-dhealaichte, agus chan eil seo idir an aon rud:

WHERE fncondX() AND fncondY()

= fncondX() && fncondY()

Anns a’ phròiseas airson plana gnìomh ceist PostgreSQL a bharrachadh faodaidh iad suidheachaidhean co-ionann “ath-rèiteachadh” gu neo-riaghailteach, na dèan cunntas air cuid dhiubh airson clàran fa leth, ceangail iad ri cumhaichean a’ chlàr-amais gnìomhaichte... Ann an ùine ghoirid, is e an dòigh as fhasa a bhith den bheachd gu bheil thu chan urrainn smachd a chumail dè an òrdugh a bhios iad (agus am bi iad air an cunntadh idir) co-ionnan cumhaichean.

Mar sin, ma tha thu fhathast airson prìomhachas a riaghladh, feumaidh tu a structaradh na cumhaichean seo a dhèanamh neo-ionann cleachdadh chumhachan abairtean и oibrichean.

Antipatterns PostgreSQL: measadh suidheachadh ann an SQL
Tha dàta agus obrachadh còmhla riutha mar bhunait an ionad VLSI againn, mar sin tha e glè chudromach dhuinne gu bheil obraichean orra air an coileanadh chan ann a-mhàin gu ceart, ach cuideachd gu h-èifeachdach. Bheir sinn sùil air eisimpleirean sònraichte far am faodar mearachdan ann an obrachadh a-mach abairtean, agus far am b’ fhiach an èifeachdas a leasachadh.

#0: RTFM

A' tòiseachadh eisimpleir bho sgrìobhainnean:

Nuair a tha òrdugh measaidh cudromach, faodar a ghlacadh a’ cleachdadh an togail CASE. Mar eisimpleir, tha seo na dhòigh air sgaradh le neoni a sheachnadh ann an seantans WHERE neo-earbsach:

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

Roghainn sàbhailte:

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

Tha an dealbhadh air a chleachdadh san dòigh seo CASE a’ dìon an abairt bho optimization, agus mar sin cha bu chòir a chleachdadh ach nuair a bhios feum air.

# 1: suidheachadh brosnachaidh

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

Tha coltas gu bheil a h-uile dad a 'coimhead math, ach ... chan eil duine a' gealltainn gum bi an tasgadh SELECT cha tèid a chur an gnìomh ma tha a’ chiad chumha meallta. Feuch an cuir sinn ceart e neadachadh IF:

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

A-nis leig dhuinn coimhead gu faiceallach - tha corp iomlan a’ ghnìomh brosnachaidh air a “fhilleadh a-steach”. IF. Tha seo a 'ciallachadh nach eil dad a' cur bacadh oirnn bho bhith a 'toirt air falbh a' chumha seo bhon mhodh-obrachaidh WHEN- suidheachaidhean:

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

Tha an dòigh-obrach seo cinnteach gun sàbhail e goireasan frithealaiche nuair a tha an suidheachadh ceàrr.

#2: NO/AND slabhraidh

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

Mur eil, faodaidh tu crìoch a chur air an dà chuid EXISTS bidh “fìor”, ach bithidh an dà chuid air an coimhlionadh.

Ach ma tha fios againn le cinnt gu bheil aon dhiubh "fìor" mòran nas trice (no "meallta" - airson AND-chains) - a bheil e comasach dòigh air choireigin “a phrìomhachas àrdachadh” gus nach tèid an dàrna fear a chuir gu bàs a-rithist?

Tha e a 'tionndadh a-mach gu bheil e comasach - an algorithmic dòigh-obrach a tha faisg air a' chuspair an artaigil Antipatterns PostgreSQL: ruigidh clàr tearc gu meadhan JOIN.

Nach dèan sinn ach “gluasad” an dà chuid de na cumhaichean sin fo CASE:

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

Anns a 'chùis seo cha do rinn sinn mìneachadh ELSE-luach, is e sin, ma tha an dà shuidheachadh ceàrr CASE tillidh NULL, a tha air a mhìneachadh mar FALSE в WHERE- suidheachaidhean.

Faodar an eisimpleir seo a chur còmhla ann an dòighean eile - a rèir blas agus dath:

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

#3: ciamar [gun] sgrìobhadh cumhachan

Chuir sinn seachad dà latha a’ dèanamh anailis air na h-adhbharan airson gnìomhachd “neònach” an inneal brosnachaidh seo - chì sinn carson.

Stòr:

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

Duilgheadas #1: chan eil neo-ionannachd a' toirt spèis do NULL

Smaoinichidh sinn gu bheil a h-uile dad OLD- bha ciall aig raointean NULL. Dè thachras?

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

Agus bho thaobh obrachadh a-mach nan suidheachaidhean NULL co-ionann FALSE, mar a chaidh ainmeachadh gu h-àrd.

co-dhùnadh: cleachd gnìomhaiche IS DISTINCT FROM от ROW-operator, a 'dèanamh coimeas eadar clàran slàn aig an aon àm:

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

Duilgheadas #2: cur an gnìomh eadar-dhealaichte den aon ghnìomhachd

Dèan coimeas:

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

Carson a tha tasgadh a bharrachd an seo? SELECT? A gnìomh to_regclass? Carson a tha e eadar-dhealaichte? ..

Dèanamaid rèiteachadh:

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

Duilgheadas #3: prìomhachas gnìomhachd bool

Feuch an cuir sinn cruth air an stòr:

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

Oops... Gu dearbh, thionndaidh e a-mach ma tha gin den chiad dà shuidheachadh fìor, gun tionndaidh an suidheachadh gu lèir gu bhith na TRUE, gun a bhith a’ toirt aire do neo-ionannachdan. Agus chan e seo idir a bha sinn ag iarraidh.

Dèanamaid rèiteachadh:

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

Duilgheadas #4 (beag): suidheachadh iom-fhillte NO airson aon raon

Gu fìrinneach, bha duilgheadasan againn ann an Àir. 3 dìreach leis gu robh trì cumhaichean ann. Ach an àite sin gheibh thu le aon, a 'cleachdadh an uidheamachd coalesce ... IN:

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

Mar sin sinn NULL “Glacaidh sinn”, agus duilich OR Chan eil feum air feansadh le camagan.

Iomlan

Nach clàraich sinn na fhuair sinn:

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

Agus ma tha thu den bheachd nach urrainnear an gnìomh brosnachaidh seo a chleachdadh ach ann an UPDATE-trigger air sgàth ruigsinneachd OLD/NEW ann an staid àrd-ìre, mar as trice faodar an suidheachadh seo a chuir a-steach WHEN-suidheachadh, mar a chithear ann an # 1 ...

Source: www.habr.com

Cuir beachd ann