PostgreSQL ضد نمونې: "یوازې باید یو وي!"

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

نن ورځ ، د خورا ساده مثالونو په کارولو سره ، راځئ وګورو چې دا د کارونې په شرایطو کې څه لامل کیدی شي GROUP/DISTINCT и LIMIT د هغوی سره.

اوس، که تاسو په غوښتنه کې لیکلي "لومړی دا نښې وصل کړئ، او بیا ټول نقلونه وباسئ، یوازې یو باید پاتې وي د هر کلی لپاره کاپي" - دا په حقیقت کې دا به څنګه کار وکړي، حتی که پیوستون ته اړتیا نه وي.

او ځینې وختونه تاسو خوشحاله یاست او دا "یوازې کار کوي"، ځینې وختونه دا په فعالیت باندې ناخوښه اغیزه لري، او ځینې وختونه دا اغیزې ورکوي چې د پراختیا کونکي له نظره په بشپړه توګه غیر متوقع وي.

PostgreSQL ضد نمونې: "یوازې باید یو وي!"
ښه، شاید دومره په زړه پورې نه وي، مګر ...

"خواږه جوړه": یوځای شئ + جلا

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

دا به روښانه شي چې دوی څه غواړي د X ریکارډونه غوره کړئ د کوم لپاره چې په Y کې ریکارډونه شتون لري چې د بشپړ شوي حالت سره تړاو لري. له لارې یوه غوښتنه لیکلې JOIN - څو ځله د pk ارزښتونه ترلاسه کړل (په دقیق ډول په Y کې څومره مناسب ننوتل څرګند شوي). څنګه لرې کول؟ یقینا DISTINCT!

دا په ځانګړي توګه "خوښونکي" دي کله چې د هر ایکس ریکارډ لپاره څو سوه اړونده Y-ریکارډونه شتون ولري ، او بیا نقلونه په زړورتیا سره لرې کیږي ...

PostgreSQL ضد نمونې: "یوازې باید یو وي!"

څنګه اصلاح کول؟ د پیل کولو لپاره، پوه شئ چې ستونزه د دې لپاره تعدیل کیدی شي "هغه ریکارډونه X غوره کړئ چې په Y کې لږترلږه یو د بشپړ شوي حالت سره تړاو لري" - په هرصورت، موږ پخپله د Y-ریکارډ څخه هیڅ شی ته اړتیا نلرو.

ځالې موجودې دي

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

د PostgreSQL ځینې نسخې پدې پوهیږي چې په موجوداتو کې دا د لومړي ننوتلو موندلو لپاره کافي دي چې راپورته کیږي ، زاړه یې نه کوي. له همدې امله زه ترجیح ورکوم چې تل اشاره وکړم 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 ضد نمونې: یو نادر ریکارډ به د یوځای کیدو مینځ ته ورسیږي".

"ولې ډیرې پیسې ورکوئ": DISTINCT [ON] + 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.

"زه باید پوښتنه وکړم": ضمني ګروپ + 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 ومومئ چې په کې راځي.

په راتلونکي کې ځینې وختونه دا ممکن د نوي نوډ څخه مننه کار وکړي Index Skip Scan، چې اوس مهال یې د پلي کولو کار روان دی ، مګر لاهم ندي.

د اوس لپاره لومړی ټول ریکارډونه به بیرته ترلاسه شي، ځانګړي دي، او یوازې له دوی څخه به غوښتل شوي مقدار بیرته راستانه شي. دا په ځانګړي ډول غمجن دی که موږ یو څه غواړو $ 1 = 4، او په جدول کې په سلګونو زره ریکارډونه شتون لري ...

د دې لپاره چې په بې ګټې غمجن نه شئ، راځئ چې تکراري پوښتنه وکاروو د PostgreSQL Wiki څخه "DISTINCT د غریبانو لپاره دی".:

PostgreSQL ضد نمونې: "یوازې باید یو وي!"

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

Add a comment