PostgreSQL Antipatterns፡ የሁኔታ ግምገማ በSQL

SQL C++ አይደለም፣ ወይም ጃቫስክሪፕት አይደለም። ስለዚህ, የሎጂክ አገላለጾች ግምገማ የተለየ ነው, እና ይህ በጭራሽ አንድ አይነት አይደለም.

WHERE fncondX() AND fncondY()

= fncondX() && fncondY()

የPostgreSQL መጠይቅን የማስፈጸሚያ እቅድ ሲያመቻቹ ተመጣጣኝ ሁኔታዎችን በዘፈቀደ "እንደገና ማስተካከል" ይችላል, ለግለሰብ መዝገቦች አንዳቸውንም አታስሉ, የተተገበረውን ኢንዴክስ ሁኔታ ይመልከቱ ... በአጭሩ ቀላሉ መንገድ እርስዎ እንደሆኑ መገመት ነው. ማስተዳደር አይችልም ቅደም ተከተላቸው (እና ጨርሶ ቢሰሉ) እኩል ነው። ሁኔታዎች.

ስለዚህ, አሁንም ቅድሚያውን ማስተዳደር ከፈለጉ, መዋቅራዊ መሆን አለብዎት እነዚህ ሁኔታዎች እኩል እንዳይሆኑ ያድርጉ ሁኔታዊ ጋር መግለጫዎች и አንቀሳቃሾች.

PostgreSQL Antipatterns፡ የሁኔታ ግምገማ በSQL
መረጃ እና ከእነሱ ጋር አብሮ መስራት መሰረት ነው የእኛ VLSI ውስብስብ, ስለዚህ በእነሱ ላይ ክዋኔዎች በትክክል ብቻ ሳይሆን በብቃት እንዲከናወኑ ለእኛ በጣም አስፈላጊ ነው. በአገላለጽ ግምገማ ውስጥ ስህተቶች ሊደረጉ የሚችሉባቸውን እና ውጤታማነታቸውን ለማሻሻል የሚረዱባቸውን ተጨባጭ ምሳሌዎችን እንመልከት።

#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-ሰንሰለቶች) - ሁለተኛው እንደገና እንዳይፈፀም በሆነ መንገድ "ቅድሚያውን ማሳደግ" ይቻላል?

የሚቻል ሆኖ ተገኝቷል - አልጎሪዝም አቀራረብ ወደ መጣጥፉ ርዕስ ቅርብ ነው። PostgreSQL Antipatterns፡ ብርቅዬ ግቤት መቀላቀል መሃል ላይ ይደርሳል.

እነዚህን ሁለቱንም ሁኔታዎች "በ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 ላይ እንደሚታየው...

ምንጭ: hab.com

አስተያየት ያክሉ