PostgreSQL Antipatterns: "አንድ ብቻ መሆን አለበት!"

በ SQL ውስጥ "ምን" ማግኘት እንደሚፈልጉ ይገልጻሉ, "እንዴት እንደሚደረግ" ሳይሆን. ስለዚህ የSQL ጥያቄዎችን የማዳበር ችግር “እንደ ተጻፈው ነው” በሚለው ዘይቤ የክብር ቦታውን ይይዛል። በ SQL ውስጥ ሁኔታዎችን የማስላት ባህሪዎች.

ዛሬ, እጅግ በጣም ቀላል ምሳሌዎችን በመጠቀም, ይህ በአጠቃቀም ሁኔታ ውስጥ ምን ሊያስከትል እንደሚችል እንይ GROUP/DISTINCT и LIMIT ከእነሱ ጋር.

አሁን, በጥያቄው ውስጥ ከጻፉ “መጀመሪያ እነዚህን ምልክቶች ያገናኙ እና ከዚያ ሁሉንም የተባዙትን ይጣሉ። አንድ ብቻ ይቀራል ለእያንዳንዱ ቁልፍ ቅዳ" - ግንኙነቱ ጨርሶ ባያስፈልግም እንኳን በትክክል የሚሰራው በዚህ መንገድ ነው።

እና አንዳንድ ጊዜ እድለኛ ነዎት እና "ልክ ይሰራል", አንዳንድ ጊዜ በአፈፃፀም ላይ ደስ የማይል ተጽእኖ ይኖረዋል, እና አንዳንድ ጊዜ ከገንቢው እይታ ሙሉ በሙሉ ያልተጠበቁ ውጤቶችን ይሰጣል.

PostgreSQL Antipatterns: "አንድ ብቻ መሆን አለበት!"
ደህና ፣ ምናልባት ያን ያህል አስደናቂ ላይሆን ይችላል ፣ ግን…

“ጣፋጭ ባልና ሚስት”፡ ይቀላቀሉ + ልዩነት

SELECT DISTINCT
  X.*
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
WHERE
  Y.bool_condition;

ምን እንደሚፈልጉ ግልጽ ይሆናል በ Y ውስጥ ከተሟላ ሁኔታ ጋር የሚዛመዱ መዝገቦች ያሉባቸውን መዝገቦች X ይምረጡ. በኩል ጥያቄ ጻፈ JOIN - አንዳንድ pk እሴቶችን ብዙ ጊዜ አግኝቷል (በ Y ውስጥ ምን ያህል ተስማሚ ግቤቶች እንደታዩ በትክክል)። እንዴት ማስወገድ እንደሚቻል? በእርግጠኝነት DISTINCT!

በተለይ ለእያንዳንዱ ኤክስ ሪከርድ ብዙ መቶ ተዛማጅ ዋይ መዛግብቶች ሲኖሩ እና ከዚያም ብዜቶቹ በጀግንነት ሲወገዱ "አስደሳች" ነው...

PostgreSQL Antipatterns: "አንድ ብቻ መሆን አለበት!"

እንዴት ማስተካከል ይቻላል? ለመጀመር, ችግሩ ወደ ሊስተካከል የሚችል መሆኑን ይገንዘቡ "መዝገብ X ምረጥ ለዚህም በ Y ውስጥ ከተሟላ ሁኔታ ጋር የተያያዘ ቢያንስ አንድ" - ከሁሉም በላይ, ከ Y-መዝገብ እራሱ ምንም ነገር አያስፈልገንም.

EXISTS መክተት

SELECT
  *
FROM
  X
WHERE
  EXISTS(
    SELECT
      NULL
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  );

አንዳንድ የPostgreSQL ስሪቶች በEXISTS ውስጥ የሚመጣውን የመጀመሪያ ግቤት ማግኘት በቂ እንደሆነ ይገነዘባሉ ፣ አዛውንቶች አያገኙም። ስለዚህ ሁልጊዜ መጠቆም እመርጣለሁ LIMIT 1 ውስጥ EXISTS.

ከጎን ይቀላቀሉ

SELECT
  X.*
FROM
  X
, LATERAL (
    SELECT
      Y.*
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  ) Y
WHERE
  Y IS DISTINCT FROM NULL;

ተመሳሳዩ አማራጭ, አስፈላጊ ከሆነ, ከተገኘው ተያያዥ የ Y-መዝገብ ላይ አንዳንድ መረጃዎችን ወዲያውኑ ለመመለስ ያስችላል. ተመሳሳይ አማራጭ በአንቀጹ ውስጥ ተብራርቷል "PostgreSQL Antipatterns፡ ብርቅዬ ሪከርድ ወደ መቀላቀል መሃል ይደርሳል".

"ለምን ተጨማሪ ይክፈሉ"፡ DISTINCT [በርቷል] + LIMIT 1

የእንደዚህ አይነት የጥያቄ ለውጦች ተጨማሪ ጥቅም በሚከተለው ሁኔታ አንድ ወይም ጥቂት ብቻ አስፈላጊ ከሆነ መዝገቦችን ፍለጋ በቀላሉ የመገደብ ችሎታ ነው።

SELECT DISTINCT ON(X.pk)
  *
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

አሁን ጥያቄውን እናነባለን እና DBMS ምን ለማድረግ እንደታሰበ ለመረዳት እንሞክራለን፡

  • ምልክቶችን በማገናኘት ላይ
  • ልዩ በ X.pk
  • ከቀሪዎቹ ግቤቶች አንዱን ይምረጡ

ታዲያ ምን አገኘህ? "አንድ ግቤት ብቻ" ልዩ ከሆኑት - እና ይህንን ልዩ ካልሆኑት ውስጥ ብንወስድ ውጤቱ በሆነ መንገድ ይቀየራል? ... "እና ምንም ልዩነት ከሌለ, ለምን የበለጠ ይከፍላሉ?"

SELECT
  *
FROM
  (
    SELECT
      *
    FROM
      X
    -- сюда можно подсунуть подходящих условий
    LIMIT 1 -- +1 Limit
  ) X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

እና በትክክል ተመሳሳይ ርዕስ GROUP BY + LIMIT 1.

"መጠየቅ አለብኝ"፡ ስውር GROUP + LIMIT

ተመሳሳይ ነገሮች በተለያየ መንገድ ይከሰታሉ ባዶ ያልሆኑ ቼኮች ጥያቄው እየገፋ ሲሄድ ምልክቶች ወይም CTEs፡-

...
CASE
  WHEN (
    SELECT
      count(*)
    FROM
      X
    LIMIT 1
  ) = 0 THEN ...

አጠቃላይ ተግባራት (count/min/max/sum/...) ያለ ግልጽ መመሪያም ቢሆን በጠቅላላው ስብስብ ላይ በተሳካ ሁኔታ ይፈጸማሉ GROUP BY. ጋር ብቻ LIMIT በጣም ተግባቢ አይደሉም።

ገንቢው ማሰብ ይችላል። "እዚያ መዝገቦች ካሉ ከ LIMIT በላይ አያስፈልገኝም". ግን ያንን አታድርጉ! ምክንያቱም ለመሠረቱ የሚከተለው ነው-

  • የሚፈልጉትን ይቁጠሩ በሁሉም መዝገቦች መሠረት
  • የጠየቁትን ያህል መስመሮችን ይስጡ

በዒላማው ሁኔታ ላይ በመመስረት ከሚከተሉት ምትክ አንዱን ማድረግ ተገቢ ነው.

  • (count + LIMIT 1) = 0 ላይ NOT EXISTS(LIMIT 1)
  • (count + LIMIT 1) > 0 ላይ EXISTS(LIMIT 1)
  • count >= N ላይ (SELECT count(*) FROM (... LIMIT N))

"በግራም ምን ያህል ይመዝናል"፡ DISTINCT + LIMIT

SELECT DISTINCT
  pk
FROM
  X
LIMIT $1

የዋህ ገንቢ ጥያቄው መፈጸሙን ያቆማል ብሎ በቅንነት ያምን ይሆናል። ከመጀመሪያዎቹ የተለያዩ ዋጋዎች ውስጥ 1 ዶላር እንዳገኘን.

አንዳንድ ጊዜ ወደፊት ይህ ለአዲስ መስቀለኛ መንገድ ምስጋና ይግባውና ሊሠራ ይችላል። ማውጫ ዝለል ቅኝት።, አተገባበሩ በአሁኑ ጊዜ እየተሰራ ነው, ግን ገና አይደለም.

ለአሁን መጀመሪያ ሁሉም መዝገቦች ተሰርስረው ይወሰዳሉ, ልዩ ናቸው, እና ከነሱ ብቻ የተጠየቀው መጠን ይመለሳል. በተለይ እንደዚህ አይነት ነገር ከፈለግን በጣም ያሳዝናል $ 1 = 4, እና በሰንጠረዡ ውስጥ በመቶ ሺዎች የሚቆጠሩ መዝገቦች አሉ ...

በከንቱ እንዳንዘን፣ ተደጋጋሚ ጥያቄን እንጠቀም "DISTINCT ለድሆች ነው" ከPostgreSQL Wiki:

PostgreSQL Antipatterns: "አንድ ብቻ መሆን አለበት!"

ምንጭ: hab.com

አስተያየት ያክሉ