PostgreSQL Antipatterns፡ ጎጂ JOINs እና ORs

ማቋቋሚያዎችን ከሚያመጡ ስራዎች ይጠንቀቁ...
ትንሽ መጠይቅን እንደ ምሳሌ በመጠቀም፣ በPostgreSQL ውስጥ መጠይቆችን ለማመቻቸት አንዳንድ ሁለንተናዊ አቀራረቦችን እንመልከት። እነሱን መጠቀም ወይም አለመጠቀም የእርስዎ ነው, ነገር ግን ስለእነሱ ማወቅ ጠቃሚ ነው.

በአንዳንድ ተከታይ የፒጂ ስሪቶች መርሐግብር አውጪው ይበልጥ ብልጥ በሚሆንበት ጊዜ ሁኔታው ​​​​ሊለወጥ ይችላል, ነገር ግን ለ 9.4/9.6 እዚህ ምሳሌዎች ውስጥ እንደሚታየው በግምት ተመሳሳይ ይመስላል.

በጣም እውነተኛ ጥያቄ እንውሰድ፡-

SELECT
  TRUE
FROM
  "Документ" d
INNER JOIN
  "ДокументРасширение" doc_ex
    USING("@Документ")
INNER JOIN
  "ТипДокумента" t_doc ON
    t_doc."@ТипДокумента" = d."ТипДокумента"
WHERE
  (d."Лицо3" = 19091 or d."Сотрудник" = 19091) AND
  d."$Черновик" IS NULL AND
  d."Удален" IS NOT TRUE AND
  doc_ex."Состояние"[1] IS TRUE AND
  t_doc."ТипДокумента" = 'ПланРабот'
LIMIT 1;

ስለ ጠረጴዛ እና የመስክ ስሞችየሜዳዎች እና የጠረጴዛዎች "የሩሲያ" ስሞች በተለየ መንገድ ሊታከሙ ይችላሉ, ግን ይህ የጣዕም ጉዳይ ነው. ምክንያቱም እዚህ በ Tensor ምንም የውጭ ገንቢዎች የሉም፣ እና PostgreSQL በሂሮግሊፍስ እንኳን ስሞችን እንድንሰጥ ያስችለናል በጥቅሶች ውስጥ ተዘግቷል, ከዚያ ምንም ልዩነቶች እንዳይኖሩ ዕቃዎችን በማያሻማ እና በግልጽ መሰየም እንመርጣለን.
የተገኘውን እቅድ እንመልከት፡-
PostgreSQL Antipatterns፡ ጎጂ JOINs እና ORs
[ማብራሪያውን ይመልከቱ.tensor.ru]

144ms እና ወደ 53ሺህ የሚጠጉ ማቋቋሚያዎች - ማለትም ከ 400MB በላይ ውሂብ! እና በጥያቄያችን ጊዜ ሁሉም በካሼው ውስጥ ካሉ እድለኞች እንሆናለን, አለበለዚያ ከዲስክ ሲነበብ ብዙ ጊዜ ይወስዳል.

አልጎሪዝም በጣም አስፈላጊ ነው!

ማንኛውንም ጥያቄ እንደምንም ለማመቻቸት መጀመሪያ ምን ማድረግ እንዳለበት መረዳት አለቦት።
የዳታቤዝ አወቃቀሩን እድገት ከዚ ጽሑፍ ወሰን ውጭ ለጊዜው እንተወውና በአንፃራዊነት “በርካሽ” እንደምንችል እንስማማለን። ጥያቄውን እንደገና ይፃፉ እና/ወይም የምንፈልጋቸውን አንዳንድ ነገሮች በመሠረቱ ላይ ያንከባለሉ ማውጫዎች.

ስለዚህ ጥያቄው:
- ቢያንስ የተወሰነ ሰነድ መኖሩን ያረጋግጣል
- በምንፈልገው ሁኔታ እና በተወሰነ ዓይነት
- ደራሲው ወይም ፈፃሚው የምንፈልገው ሰራተኛ ከሆነ

ይቀላቀሉ + LIMIT 1

ብዙ ሠንጠረዦች መጀመሪያ የተቀላቀሉበት ጥያቄ ለመጻፍ ብዙ ጊዜ ለገንቢ ይቀላል፣ እና ከዚያ ከዚህ ስብስብ አንድ መዝገብ ብቻ ይቀራል። ግን ለገንቢው ቀላል ማለት ለዳታቤዝ የበለጠ ቀልጣፋ ማለት አይደለም።
በእኛ ሁኔታ 3 ጠረጴዛዎች ብቻ ነበሩ - ውጤቱስ ምንድ ነው?

በመጀመሪያ ከ "የሰነድ አይነት" ሰንጠረዥ ጋር ያለውን ግንኙነት እናስወግድ, እና በተመሳሳይ ጊዜ የውሂብ ጎታውን ይንገሩ የኛ አይነት መዝገብ ልዩ ነው። (ይህን እናውቃለን፣ ግን የጊዜ ሰሌዳ አስማሚው እስካሁን ምንም ሀሳብ የለውም)

WITH T AS (
  SELECT
    "@ТипДокумента"
  FROM
    "ТипДокумента"
  WHERE
    "ТипДокумента" = 'ПланРабот'
  LIMIT 1
)
...
WHERE
  d."ТипДокумента" = (TABLE T)
...

አዎ፣ ሠንጠረዡ/CTE የአንድ ሪከርድ አንድ ነጠላ መስክ ካካተተ፣በፒጂ ውስጥ ከመፃፍ ይልቅ እንደዚህ መፃፍ ይችላሉ።

d."ТипДокумента" = (SELECT "@ТипДокумента" FROM T LIMIT 1)

በPostgreSQL መጠይቆች ውስጥ ሰነፍ ግምገማ

BitmapOr vs UNION

በአንዳንድ ሁኔታዎች ቢትማፕ ሂፕ ስካን ብዙ ያስከፍለናል - ለምሳሌ በእኛ ሁኔታ ብዙ መዝገቦች የሚፈለገውን ሁኔታ ሲያሟሉ። ያገኘነው ምክንያቱም ወይም ሁኔታ ወደ BitmapOr ተለወጠ- በእቅድ ውስጥ ክወና.
ወደ መጀመሪያው ችግር እንመለስ - ተዛማጅ መዝገብ ማግኘት አለብን ማንኛውም ከሁኔታዎች - ማለትም በሁለቱም ሁኔታዎች ሁሉንም 59K መዛግብት መፈለግ አያስፈልግም. አንድ ሁኔታን ለመሥራት አንድ መንገድ አለ, እና በመጀመሪያው ላይ ምንም ነገር ካልተገኘ ብቻ ወደ ሁለተኛው ይሂዱ. የሚከተለው ንድፍ ይረዳናል:

(
  SELECT
    ...
  LIMIT 1
)
UNION ALL
(
  SELECT
    ...
  LIMIT 1
)
LIMIT 1

"ውጫዊ" LIMIT 1 ፍለጋው የሚያበቃው የመጀመሪያው መዝገብ ሲገኝ መሆኑን ያረጋግጣል። እና በመጀመሪያው እገዳ ውስጥ ቀድሞውኑ ከተገኘ, ሁለተኛው እገዳ አይተገበርም (ፈጽሞ አልተገደለም በተመለከተ)።

"በ CASE ስር አስቸጋሪ ሁኔታዎችን መደበቅ"

በመጀመሪያው መጠይቅ ውስጥ በጣም የማይመች ጊዜ አለ - ሁኔታውን ከተዛማጅ ሠንጠረዥ "ሰነድ ኤክስቴንሽን" ጋር መፈተሽ። በገለፃው ውስጥ ያሉ ሌሎች ሁኔታዎች እውነት ምንም ቢሆኑም (ለምሳሌ ፣ መ.“ተሰርዟል” እውነት አይደለም።), ይህ ግንኙነት ሁል ጊዜ ይከናወናል እና "ሀብቶችን ያስከፍላል". ከእነሱ ብዙ ወይም ያነሰ ወጪ ይደረጋል - በዚህ ሰንጠረዥ መጠን ይወሰናል.
ግን ተዛማጅነት ያለው መዝገብ መፈለግ በጣም አስፈላጊ በሚሆንበት ጊዜ ብቻ እንዲከሰት መጠይቁን ማስተካከል ይችላሉ፡

SELECT
  ...
FROM
  "Документ" d
WHERE
  ... /*index cond*/ AND
  CASE
    WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
      SELECT
        "Состояние"[1] IS TRUE
      FROM
        "ДокументРасширение"
      WHERE
        "@Документ" = d."@Документ"
    )
  END

አንዴ ከተገናኘው ጠረጴዛ ወደ እኛ ለውጤቱ የትኛውም መስክ አያስፈልግም, ከዚያ JOINን በንዑስ መጠይቅ ላይ ወደ ሁኔታ የመቀየር እድል አለን።
በመረጃ ጠቋሚ የተቀመጡትን መስኮች “ከ CASE ቅንፎች ውጭ” እንተዋቸው ፣ ቀላል ሁኔታዎችን ከመዝገቡ ወደ WHEN ብሎክ እንጨምር - እና አሁን “ከባድ” መጠይቁ የሚከናወነው ወደ THEN ሲያልፍ ብቻ ነው።

የመጨረሻ ስሜ "ጠቅላላ" ነው

ውጤቱን ከላይ ከተገለጹት ሁሉም መካኒኮች ጋር እንሰበስባለን-

WITH T AS (
  SELECT
    "@ТипДокумента"
  FROM
    "ТипДокумента"
  WHERE
    "ТипДокумента" = 'ПланРабот'
)
  (
    SELECT
      TRUE
    FROM
      "Документ" d
    WHERE
      ("Лицо3", "ТипДокумента") = (19091, (TABLE T)) AND
      CASE
        WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
          SELECT
            "Состояние"[1] IS TRUE
          FROM
            "ДокументРасширение"
          WHERE
            "@Документ" = d."@Документ"
        )
      END
    LIMIT 1
  )
UNION ALL
  (
    SELECT
      TRUE
    FROM
      "Документ" d
    WHERE
      ("ТипДокумента", "Сотрудник") = ((TABLE T), 19091) AND
      CASE
        WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
          SELECT
            "Состояние"[1] IS TRUE
          FROM
            "ДокументРасширение"
          WHERE
            "@Документ" = d."@Документ"
        )
      END
    LIMIT 1
  )
LIMIT 1;

[ወደ] ኢንዴክሶች በማስተካከል ላይ

የሰለጠነ ዓይን በ UNION ንዑስ ብሎኮች ውስጥ ያሉት ጠቋሚ ሁኔታዎች ትንሽ ለየት ያሉ መሆናቸውን አስተውሏል - ይህ የሆነበት ምክንያት በጠረጴዛው ላይ ተስማሚ ኢንዴክሶች ስላሉን ነው። እና እነሱ ከሌሉ ፣ መፍጠር ጠቃሚ ይሆናል- ሰነድ (ሰው 3፣ ሰነድ ዓይነት) и ሰነድ (የሰነድ ዓይነት፣ ተቀጣሪ).
በ ROW ሁኔታዎች ውስጥ ስለ መስኮች ቅደም ተከተልከእቅድ አውጪው እይታ, በእርግጥ, መጻፍ ይችላሉ (A፣ B) = (constA፣ constB)(B፣ A) = (constB፣ constA). ነገር ግን በሚቀዳበት ጊዜ በመረጃ ጠቋሚው ውስጥ ባሉት መስኮች ቅደም ተከተል, እንዲህ ዓይነቱ ጥያቄ በኋላ ላይ ለማረም በቀላሉ የበለጠ አመቺ ነው.
በእቅዱ ውስጥ ምን አለ?
PostgreSQL Antipatterns፡ ጎጂ JOINs እና ORs
[ማብራሪያውን ይመልከቱ.tensor.ru]

እንደ አለመታደል ሆኖ እኛ እድለኞች አልነበርንም እና በመጀመሪያው UNION ብሎክ ውስጥ ምንም ነገር አልተገኘም, ስለዚህ ሁለተኛው አሁንም ተገድሏል. ግን እንደዚያም - ብቻ 0.037ms እና 11 ቋቶች!
ጥያቄውን አፋጥነናል እና በሜሞሪ ውስጥ ያለውን የመረጃ ፍሰት ቀንሷል ብዙ ሺህ ጊዜ, በአግባቡ ቀላል ቴክኒኮችን በመጠቀም - ጥሩ ውጤት በትንሽ ኮፒ-መለጠፍ. 🙂

ምንጭ: hab.com

አስተያየት ያክሉ