PostgreSQL ضد نمونې: زیان رسونکي یوځای کیدل او ORs

د هغو عملیاتو څخه خبر اوسئ چې بفرونه راوړي ...
د مثال په توګه د یوې کوچنۍ پوښتنې په کارولو سره، راځئ چې په PostgreSQL کې د پوښتنو غوره کولو لپاره ځینې نړیوال چلندونه وګورو. که تاسو یې وکاروئ یا نه ستاسو پورې اړه لري ، مګر دا د دوی په اړه پوهیدل ارزښت لري.

د PG په ځینو راتلونکو نسخو کې وضعیت ممکن بدلون ومومي ځکه چې مهالویش سمارټ کیږي، مګر د 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;

د میز او ساحې نومونو په اړهد ساحو او میزونو "روسی" نومونه په مختلف ډول چلند کیدی شي، مګر دا د خوند خبره ده. ځکه چې د دلته په ټینسر کې هیڅ بهرني پراختیا کونکي شتون نلري ، او PostgreSQL موږ ته اجازه راکوي حتی په هیروګلیفونو کې نومونه راکړو ، که دوی په نرخونو کې تړل شوي، بیا موږ غوره کوو چې د شیانو نومونه په واضح او واضح ډول ولیکئ ترڅو هیڅ توپیر شتون ونلري.
راځئ چې پایله لرونکی پلان وګورو:
PostgreSQL ضد نمونې: زیان رسونکي یوځای کیدل او ORs
[ تشریح.tensor.ru ته وګورئ]

144ms او نږدې 53K بفرونه - دا د 400MB څخه ډیر ډیټا دی! او موږ به خوشحاله یو که دا ټول زموږ د غوښتنې په وخت کې په زیرمه کې وي، که نه نو دا به د ډیسک څخه لوستلو کې څو ځله ډیر وخت ونیسي.

الګوریتم خورا مهم دی!

د دې لپاره چې په یو څه ډول کومه غوښتنه اصلاح کړئ، تاسو باید لومړی پوه شئ چې دا باید څه وکړي.
راځئ چې د اوس لپاره د دې مقالې له ساحې بهر د ډیټابیس جوړښت پراختیا پریږدو، او موافقه وکړو چې موږ کولی شو نسبتا "ارزانه" غوښتنه بیا ولیکئ او/یا ځینې شیان چې موږ ورته اړتیا لرو په بیس کې رول کړئ شاخصونه.

نو دا غوښتنه:
- لږترلږه د یو څه سند شتون چک کوي
- په هغه حالت کې چې موږ ورته اړتیا لرو او یو ځانګړي ډول
- چیرې چې لیکوال یا اداکار هغه کارمند دی چې موږ ورته اړتیا لرو

ګډون + محدودیت 1

ډیری وختونه د پراختیا کونکي لپاره دا اسانه وي چې یوه پوښتنه ولیکئ چیرې چې لوی شمیر میزونه لومړی سره یوځای کیږي ، او بیا د دې ټول سیټ څخه یوازې یو ریکارډ پاتې کیږي. مګر د پراختیا کونکي لپاره اسانه د ډیټابیس لپاره ډیر اغیزمن معنی نلري.
زموږ په قضیه کې یوازې 3 میزونه وو - او اغیز څه دی ...

راځئ چې لومړی د "د سند ډول" جدول سره اړیکې لرې کړو او په ورته وخت کې ډیټابیس ته ووایو چې زموږ ډول ریکارډ ځانګړی دی (موږ دا پوهیږو، مګر مهالویش تر اوسه نه پوهیږي):

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

هو، که جدول/CTE د یو واحد ریکارډ یوه ساحه ولري، نو بیا په PG کې تاسو حتی د دې په ځای لیکلی شئ

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

په PostgreSQL پوښتنو کې سست ارزونه

BitmapOr vs UNION

په ځینو مواردو کې، د بټ میپ هیپ سکین به موږ ته ډیر لګښت ورکړي - د بیلګې په توګه، زموږ په وضعیت کې، کله چې ډیری ریکارډونه اړین شرایط پوره کوي. موږ دا ترلاسه کړل ځکه OR حالت په BitmapOr بدل شو- په پلان کې عملیات.
راځئ چې اصلي ستونزې ته راستون شو - موږ اړتیا لرو چې ورته ریکارډ ومومئ هر څوک د شرایطو څخه - دا دی، د دواړو شرایطو لاندې د ټولو 59K ریکارډونو لټون ته اړتیا نشته. د یو شرط کار کولو لپاره یوه لاره شتون لري، او دوهم ته لاړشئ یوازې کله چې په لومړي کې هیڅ ونه موندل شو. لاندې ډیزاین به موږ سره مرسته وکړي:

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

"بهرنۍ" LIMIT 1 ډاډ ترلاسه کوي چې لټون پای ته رسیږي کله چې لومړی ریکارډ وموندل شي. او که دا دمخه په لومړي بلاک کې وموندل شي ، دوهم بلاک به اجرا نشي (هیڅکله نه اعدام شوی په اړه).

"د قضیې لاندې د سختو شرایطو پټول"

په اصلي پوښتنه کې خورا ناامنه شیبه شتون لري - د اړوند میز "د سند توسیع" په وړاندې د وضعیت معاینه کول. په بیان کې د نورو شرایطو حقیقت ته په پام سره (د مثال په توګه، d. "ړنګول" ریښتیا ندي)، دا اړیکه تل اجرا کیږي او "سرچینې لګښت کوي". د دوی څخه ډیر یا لږ به مصرف شي - د دې میز په اندازې پورې اړه لري.
مګر تاسو کولی شئ پوښتنه تعدیل کړئ ترڅو د اړوند ریکارډ لټون یوازې هغه وخت پیښ شي کله چې واقعیا اړین وي:

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

یوځل له تړل شوي میز څخه موږ ته د پایلې لپاره هیڅ یوې ساحې ته اړتیا نشته، بیا موږ فرصت لرو چې ګډون په یوه فرعي پوښتنې کې په شرط بدل کړو.
راځئ چې شاخص شوي ساحې "د 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 ضد نمونې: زیان رسونکي یوځای کیدل او ORs
[ تشریح.tensor.ru ته وګورئ]

له بده مرغه، موږ بدبخته یو او د یونین په لومړي بلاک کې هیڅ شی ونه موندل شو، نو دویم یې لاهم اعدام شو. مګر حتی حتی - یوازې 0.037ms او 11 بفرونه!
موږ غوښتنه ګړندۍ کړې او په حافظه کې د ډیټا پمپ کول کم شوي څو زره ځلهد کافي ساده تخنیکونو په کارولو سره - د لږ کاپي پیسټ سره ښه پایله. 🙂

سرچینه: www.habr.com

Add a comment