PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursion

เบŠเป‰เบณ - เบเบปเบ™เป„เบเบ—เบตเปˆเบกเบตเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเปเบฅเบฐเบชเบฐเบ”เบงเบเบซเบผเบฒเบเบ–เป‰เบฒเบซเบฒเบเบงเปˆเบฒเบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ” "เปƒเบ™เบ„เบงเบฒเบกเป€เบฅเบดเบ" เบ”เบฝเบงเบเบฑเบ™เบเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบ—เบตเปˆเบเปˆเบฝเบงเบ‚เป‰เบญเบ‡. เปเบ•เปˆ recursion uncontrolled เปเบกเปˆเบ™เบ„เบงเบฒเบกเบŠเบปเปˆเบงเบฎเป‰เบฒเบเบ—เบตเปˆเบชเบฒเบกเบฒเบ”เบ™เปเบฒเป„เบ›เบชเบนเปˆเบเบฒเบ™เบšเปเปˆเบงเปˆเบฒเบˆเบฐ เบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ”เบ—เบตเปˆเบšเปเปˆเบกเบตเบ—เบตเปˆเบชเบดเป‰เบ™เบชเบธเบ” เบ‚เบฐเบšเบงเบ™เบเบฒเบ™, เบซเบผเบท (เบ—เบตเปˆเป€เบเบตเบ”เบ‚เบทเป‰เบ™เป€เบฅเบทเป‰เบญเบเป†) เบเบฑเบš "เบเบดเบ™" เบ„เบงเบฒเบกเบŠเบปเบ‡เบˆเปเบฒเบ—เบตเปˆเบกเบตเบขเบนเปˆเบ—เบฑเบ‡เบซเบกเบปเบ”.

PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursion
DBMS เปƒเบ™เป€เบฅเบทเปˆเบญเบ‡เบ™เบตเป‰เป€เบฎเบฑเบ”เบงเบฝเบเบขเบนเปˆเปƒเบ™เบซเบผเบฑเบเบเบฒเบ™เบ”เบฝเบงเบเบฑเบ™ - "เบžเบงเบเป€เบ‚เบปเบฒเบšเบญเบเบ‚เป‰เบญเบเปƒเบซเป‰เบ‚เบธเบ”, เบชเบฐเบ™เบฑเป‰เบ™เบ‚เป‰เบญเบเบ‚เบธเบ”". เบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเบ‚เบญเบ‡เบ—เปˆเบฒเบ™เบšเปเปˆเบžเบฝเบ‡เปเบ•เปˆเบชเบฒเบกเบฒเบ”เบŠเป‰เบฒเบฅเบปเบ‡เบ‚เบฐเบšเบงเบ™เบเบฒเบ™เปƒเบเป‰เบ„เบฝเบ‡, เบชเบทเบšเบ•เปเปˆเปƒเบŠเป‰เบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เบ‚เบญเบ‡เป‚เบ›เป€เบŠเบ”เป€เบŠเบต, เปเบ•เปˆเบเบฑเบ‡ "เบฅเบธเบ”เบฅเบปเบ‡" เบ–เบฒเบ™เบ‚เปเป‰เบกเบนเบ™เบ—เบฑเบ‡เบซเบกเบปเบ”, "เบเบดเบ™" เบซเบ™เปˆเบงเบเบ„เบงเบฒเบกเบˆเปเบฒเบ—เบตเปˆเบกเบตเบขเบนเปˆเบ—เบฑเบ‡เบซเบกเบปเบ”. เบเบฒเบ™โ€‹เบ›เบปเบโ€‹เบ›เบฑเบโ€‹เบฎเบฑเบโ€‹เบชเบฒโ€‹เบ•เป‰เบฒเบ™โ€‹เบเบฒเบ™ recursion infiniteโ€‹ - เบ„เบงเบฒเบกเบฎเบฑเบšเบœเบดเบ”เบŠเบญเบšเบ‚เบญเบ‡เบœเบนเป‰เบžเบฑเบ”เบ—เบฐเบ™เบฒเป€เบญเบ‡.

เปƒเบ™ PostgreSQL, เบ„เบงเบฒเบกเบชเบฒเบกเบฒเบ”เปƒเบ™เบเบฒเบ™เปƒเบŠเป‰เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก recursive เบœเปˆเบฒเบ™ WITH RECURSIVE เบ›เบฐเบเบปเบ”เบขเบนเปˆเปƒเบ™เป€เบงเบฅเบฒเบšเปเปˆเบ”เบปเบ™เบ™เบฒเบ™เบ‚เบญเบ‡เป€เบงเบตเบŠเบฑเบ™ 8.4, เปเบ•เปˆเบ—เปˆเบฒเบ™เบเบฑเบ‡เบชเบฒเบกเบฒเบ”เบžเบปเบšเบเบฑเบšเบเบฒเบ™เบชเบญเบšเบ–เบฒเบก "defenseless" เบ—เบตเปˆเบกเบตเบ„เบงเบฒเบกเบชเปˆเบฝเบ‡เป€เบ›เบฑเบ™เบ›เบฐเบˆเปเบฒ. เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบˆเบฑเบ”เบ•เบปเบงเบ—เปˆเบฒเบ™เป€เบญเบ‡เบˆเบฒเบเบšเบฑเบ™เบซเบฒเบ›เบฐเป€เบžเบ”เบ™เบตเป‰?

เบขเปˆเบฒเบ‚เบฝเบ™เปเบšเบšเบชเบญเบšเบ–เบฒเบกเบŠเป‰เบณเป†

เปเบฅเบฐเบ‚เบฝเบ™เบชเบดเปˆเบ‡เบ—เบตเปˆเบšเปเปˆเบŠเปเป‰เบฒเบเบฑเบ™. เบ”เป‰เบงเบเบ„เบงเบฒเบกเบ™เบฑเบšเบ–เบท, K.O.

เปƒเบ™เบ„เบงเบฒเบกเป€เบ›เบฑเบ™เบˆเบดเบ‡, PostgreSQL เบชเบฐเบซเบ™เบญเบ‡เบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบซเบผเบฒเบเบขเปˆเบฒเบ‡เบ—เบตเปˆเบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ™เปเบฒเปƒเบŠเป‰เป„เบ”เป‰ เบšเปเปˆ เบ™เบณเปƒเบŠเป‰ recursion.

เปƒเบŠเป‰เบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเปˆเปเบ•เบเบ•เปˆเบฒเบ‡เบเบฑเบ™เป‚เบ”เบเบžเบทเป‰เบ™เบ–เบฒเบ™เบเบฑเบšเบšเบฑเบ™เบซเบฒ

เบšเบฒเบ‡เบ„เบฑเป‰เบ‡เบ—เปˆเบฒเบ™เบžเบฝเบ‡เปเบ•เปˆเบชเบฒเบกเบฒเบ”เป€เบšเบดเปˆเบ‡เบšเบฑเบ™เบซเบฒเบˆเบฒเบ "เบ”เป‰เบฒเบ™เบ—เบตเปˆเปเบ•เบเบ•เปˆเบฒเบ‡เบเบฑเบ™". เบ‚เป‰เบฒเบžเบฐเป€เบˆเบปเป‰เบฒเป„เบ”เป‰เบเบปเบเบ•เบปเบงเบขเปˆเบฒเบ‡เบ‚เบญเบ‡เบชเบฐเบ–เบฒเบ™เบฐเบเบฒเบ™เบ”เบฑเปˆเบ‡เบเปˆเบฒเบงเปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบก "SQL HowTo: 1000 เปเบฅเบฐเบงเบดเบ—เบตเบซเบ™เบถเปˆเบ‡เบ‚เบญเบ‡เบเบฒเบ™เบฅเบงเบšเบฅเบงเบก" โ€” เบเบฒเบ™โ€‹เบ„เบนเบ™โ€‹เบ‚เบญเบ‡โ€‹เบŠเบธเบ”โ€‹เบ‚เบญเบ‡โ€‹เบ•เบปเบงโ€‹เป€เบฅเบโ€‹เป‚เบ”เบโ€‹เบšเปเปˆโ€‹เบกเบตโ€‹เบเบฒเบ™โ€‹เบ™เปเบฒโ€‹เปƒเบŠเป‰โ€‹เบซเบ™เป‰เบฒโ€‹เบ—เบตเปˆโ€‹เบฅเบงเบกโ€‹เบ—เบตเปˆโ€‹เบเปเบฒโ€‹เบ™เบปเบ”โ€‹เป€เบญเบ‡โ€‹:

WITH RECURSIVE src AS (
  SELECT '{2,3,5,7,11,13,17,19}'::integer[] arr
)
, T(i, val) AS (
  SELECT
    1::bigint
  , 1
UNION ALL
  SELECT
    i + 1
  , val * arr[i]
  FROM
    T
  , src
  WHERE
    i <= array_length(arr, 1)
)
SELECT
  val
FROM
  T
ORDER BY -- ะพั‚ะฑะพั€ ั„ะธะฝะฐะปัŒะฝะพะณะพ ั€ะตะทัƒะปัŒั‚ะฐั‚ะฐ
  i DESC
LIMIT 1;

เบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเบ™เบตเป‰เบชเบฒเบกเบฒเบ”เบ–เบทเบเปเบ—เบ™เบ—เบตเปˆเบ”เป‰เบงเบเบ—เบฒเบ‡เป€เบฅเบทเบญเบเบˆเบฒเบเบœเบนเป‰เบŠเปˆเบฝเบงเบŠเบฒเบ™เบ”เป‰เบฒเบ™เบ„เบฐเบ™เบดเบ”เบชเบฒเบ”:

WITH src AS (
  SELECT unnest('{2,3,5,7,11,13,17,19}'::integer[]) prime
)
SELECT
  exp(sum(ln(prime)))::integer val
FROM
  src;

เปƒเบŠเป‰ generate_series เปเบ—เบ™ loops

เบชเบปเบกเบกเบธเบ”เบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบเปเบฒเบฅเบฑเบ‡เบ›เบฐเป€เบŠเบตเบ™เบเบฑเบšเบงเบฝเบเบ‡เบฒเบ™เบ‚เบญเบ‡เบเบฒเบ™เบชเป‰เบฒเบ‡เบ„เปเบฒเบ™เปเบฒเบซเบ™เป‰เบฒเบ—เบตเปˆเป€เบ›เบฑเบ™เป„เบ›เป„เบ”เป‰เบ—เบฑเบ‡เบซเบกเบปเบ”เบชเปเบฒเบฅเบฑเบš string 'abcdefgh':

WITH RECURSIVE T AS (
  SELECT 'abcdefgh' str
UNION ALL
  SELECT
    substr(str, 1, length(str) - 1)
  FROM
    T
  WHERE
    length(str) > 1
)
TABLE T;

เบ—เปˆเบฒเบ™เปเบ™เปˆเปƒเบˆเบšเปเปˆเบงเปˆเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™ recursion เบขเบนเปˆเบ—เบตเปˆเบ™เบตเป‰?.. เบ–เป‰เบฒเป€เบˆเบปเป‰เบฒเปƒเบŠเป‰ LATERAL ะธ generate_seriesเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™, เบ—เปˆเบฒเบ™เบˆเบฐเบšเปเปˆเบ•เป‰เบญเบ‡เบเบฒเบ™ CTE:

SELECT
  substr(str, 1, ln) str
FROM
  (VALUES('abcdefgh')) T(str)
, LATERAL(
    SELECT generate_series(length(str), 1, -1) ln
  ) X;

เบ›เปˆเบฝเบ™เป‚เบ„เบ‡เบชเป‰เบฒเบ‡เบ–เบฒเบ™เบ‚เปเป‰เบกเบนเบ™

เบ•เบปเบงเบขเปˆเบฒเบ‡, เบ—เปˆเบฒเบ™เบกเบตเบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบ‚เปเป‰เบ„เบงเบฒเบกเบ‚เบญเบ‡เป€เบงเบ—เบตเบชเบปเบ™เบ—เบฐเบ™เบฒเบ—เบตเปˆเบกเบตเบเบฒเบ™เป€เบŠเบทเปˆเบญเบกเบ•เปเปˆเบˆเบฒเบเบœเบนเป‰เบ—เบตเปˆเบ•เบญเบšเบชเบฐเบซเบ™เบญเบ‡เบเบฑเบšเปƒเบœ, เบซเบผเบทเบซเบปเบงเบ‚เปเป‰เปƒเบ™ เป€เบ„เบทเบญโ€‹เบ‚เปˆเบฒเบโ€‹เบชเบฑเบ‡โ€‹เบ„เบปเบก:

CREATE TABLE message(
  message_id
    uuid
      PRIMARY KEY
, reply_to
    uuid
      REFERENCES message
, body
    text
);
CREATE INDEX ON message(reply_to);

PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursion
เบ”เบต, เบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเบ›เบปเบเบเบฐเบ•เบดเป€เบžเบทเปˆเบญเบ”เบฒเบงเป‚เบซเบฅเบ”เบ‚เปเป‰เบ„เบงเบฒเบกเบ—เบฑเบ‡เบซเบกเบปเบ”เปƒเบ™เบซเบปเบงเบ‚เปเป‰เบซเบ™เบถเปˆเบ‡เป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเบšเบฒเบ‡เบชเบดเปˆเบ‡เบšเบฒเบ‡เบขเปˆเบฒเบ‡เป€เบŠเบฑเปˆเบ™เบ™เบตเป‰:

WITH RECURSIVE T AS (
  SELECT
    *
  FROM
    message
  WHERE
    message_id = $1
UNION ALL
  SELECT
    m.*
  FROM
    T
  JOIN
    message m
      ON m.reply_to = T.message_id
)
TABLE T;

เปเบ•เปˆเป€เบ™เบทเปˆเบญเบ‡เบˆเบฒเบเบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบชเบฐเป€เบซเบกเบตเบ•เป‰เบญเบ‡เบเบฒเบ™เบซเบปเบงเบ‚เปเป‰เบ—เบฑเบ‡เบซเบกเบปเบ”เบˆเบฒเบเบ‚เปเป‰เบ„เบงเบฒเบกเบฎเบฒเบ, เปเบฅเป‰เบงเป€เบ›เบฑเบ™เบซเบเบฑเบ‡เบžเบงเบเป€เบฎเบปเบฒเบšเปเปˆ เป€เบžเบตเปˆเบก ID เบ‚เบญเบ‡เบกเบฑเบ™เปƒเบชเปˆเปเบ•เปˆเบฅเบฐเบฅเบฒเบเบเบฒเบ™ เบญเบฑเบ”เบ•เบฐเป‚เบ™เบกเบฑเบ”?

-- ะดะพะฑะฐะฒะธะผ ะฟะพะปะต ั ะพะฑั‰ะธะผ ะธะดะตะฝั‚ะธั„ะธะบะฐั‚ะพั€ะพะผ ั‚ะตะผั‹ ะธ ะธะฝะดะตะบั ะฝะฐ ะฝะตะณะพ
ALTER TABLE message
  ADD COLUMN theme_id uuid;
CREATE INDEX ON message(theme_id);

-- ะธะฝะธั†ะธะฐะปะธะทะธั€ัƒะตะผ ะธะดะตะฝั‚ะธั„ะธะบะฐั‚ะพั€ ั‚ะตะผั‹ ะฒ ั‚ั€ะธะณะณะตั€ะต ะฟั€ะธ ะฒัั‚ะฐะฒะบะต
CREATE OR REPLACE FUNCTION ins() RETURNS TRIGGER AS $$
BEGIN
  NEW.theme_id = CASE
    WHEN NEW.reply_to IS NULL THEN NEW.message_id -- ะฑะตั€ะตะผ ะธะท ัั‚ะฐั€ั‚ะพะฒะพะณะพ ัะพะฑั‹ั‚ะธั
    ELSE ( -- ะธะปะธ ะธะท ัะพะพะฑั‰ะตะฝะธั, ะฝะฐ ะบะพั‚ะพั€ะพะต ะพั‚ะฒะตั‡ะฐะตะผ
      SELECT
        theme_id
      FROM
        message
      WHERE
        message_id = NEW.reply_to
    )
  END;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER ins BEFORE INSERT
  ON message
    FOR EACH ROW
      EXECUTE PROCEDURE ins();

PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursion
เปƒเบ™เบ›เบฑเบ”เบˆเบธเบšเบฑเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก recursive เบ—เบฑเบ‡เบซเบกเบปเบ”เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบซเบผเบธเบ”เบฅเบปเบ‡เบžเบฝเบ‡เปเบ•เปˆเบ™เบตเป‰:

SELECT
  *
FROM
  message
WHERE
  theme_id = $1;

เปƒเบŠเป‰ "เบ‚เบตเบ”เบˆเปเบฒเบเบฑเบ”" เบ—เบตเปˆเปƒเบŠเป‰เปเบฅเป‰เบง

เบ–เป‰เบฒเบžเบงเบเป€เบฎเบปเบฒเบšเปเปˆเบชเบฒเบกเบฒเบ”เบ›เปˆเบฝเบ™เป‚เบ„เบ‡เบชเป‰เบฒเบ‡เบ‚เบญเบ‡เบ–เบฒเบ™เบ‚เปเป‰เบกเบนเบ™เป„เบ”เป‰เบ”เป‰เบงเบเป€เบซเบ”เบœเบปเบ™เบšเบฒเบ‡เบขเปˆเบฒเบ‡, เปƒเบซเป‰เป€เบšเบดเปˆเบ‡เบชเบดเปˆเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบญเบตเบ‡เปƒเบชเปˆเป€เบžเบทเปˆเบญเบงเปˆเบฒเป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเบเบฒเบ™เบ›เบฐเบเบปเบ”เบ•เบปเบงเบ‚เบญเบ‡เบ‚เปเป‰เบœเบดเบ”เบžเบฒเบ”เปƒเบ™เบ‚เปเป‰เบกเบนเบ™เบเปเปˆเบšเปเปˆเบ™เปเบฒเป„เบ›เบชเบนเปˆเบเบฒเบ™เป€เบญเบตเป‰เบ™เบ„เบทเบ™เบ—เบตเปˆเบšเปเปˆเบชเบดเป‰เบ™เบชเบธเบ”.

เบ•เบปเบงเบ™เบฑเบšเบ„เบงเบฒเบกเป€เบฅเบดเบ Recursion

เบžเบงเบเป€เบฎเบปเบฒเบžเบฝเบ‡เปเบ•เปˆเป€เบžเบตเปˆเบกเบเบฒเบ™เบ™เบฑเบšเบ–เบญเบเบซเบผเบฑเบ‡เป€เบ—เบทเปˆเบญเบฅเบฐเบญเบฑเบ™เปƒเบ™เปเบ•เปˆเบฅเบฐเบ‚เบฑเป‰เบ™เบ•เบญเบ™ recursion เบˆเบปเบ™เบเปˆเบงเบฒเบžเบงเบเป€เบฎเบปเบฒเบšเบฑเบ™เบฅเบธเบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ–เบทเบงเปˆเบฒเบšเปเปˆเบžเบฝเบ‡เบžเปเบขเปˆเบฒเบ‡เบˆเบฐเปเบˆเป‰เบ‡:

WITH RECURSIVE T AS (
  SELECT
    0 i
  ...
UNION ALL
  SELECT
    i + 1
  ...
  WHERE
    T.i < 64 -- ะฟั€ะตะดะตะป
)

Pro: เปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบžเบฐเบเบฒเบเบฒเบก loop, เบžเบงเบเป€เบฎเบปเบฒเบเบฑเบ‡เบˆเบฐเป€เบฎเบฑเบ”เบšเปเปˆเป€เบเบตเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”เบ‚เบญเบ‡ iterations "เปƒเบ™เบ„เบงเบฒเบกเป€เบฅเบดเบ".
cons: เบšเปเปˆเบกเบตเบเบฒเบ™เบฎเบฑเบšเบ›เบฐเบเบฑเบ™เบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบšเปเปˆเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบšเบฑเบ™เบ—เบถเบเบ”เบฝเบงเบเบฑเบ™เบญเบตเบเป€เบ—เบทเปˆเบญเบซเบ™เบถเปˆเบ‡ - เบ•เบปเบงเบขเปˆเบฒเบ‡, เบขเบนเปˆเบ—เบตเปˆเบ„เบงเบฒเบกเป€เบฅเบดเบ 15 เปเบฅเบฐ 25, เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบ—เบธเบเป† +10. เปเบฅเบฐเบšเปเปˆเบกเบตเปƒเบœเบชเบฑเบ™เบเบฒเบซเบเบฑเบ‡เบเปˆเบฝเบงเบเบฑเบš "เบ„เบงเบฒเบกเบเบงเป‰เบฒเบ‡".

เบขเปˆเบฒเบ‡เป€เบ›เบฑเบ™เบ—เบฒเบ‡เบเบฒเบ™, เบเบฒเบ™เป€เบญเบตเป‰เบ™เบ„เบทเบ™เบ”เบฑเปˆเบ‡เบเปˆเบฒเบงเบˆเบฐเบšเปเปˆเป€เบ›เบฑเบ™เบญเบฑเบ™เป€เบ›เบฑเบ™เบ™เบดเบ”, เปเบ•เปˆเบ–เป‰เบฒเปเบ•เปˆเบฅเบฐเบ‚เบฑเป‰เบ™เบ•เบญเบ™เบˆเปเบฒเบ™เบงเบ™เบšเบฑเบ™เบ—เบถเบเป€เบžเบตเปˆเบกเบ‚เบถเป‰เบ™เป€เบ›เบฑเบ™เป€เบฅเบเป€เบฅเบ, เบžเบงเบเป€เบฎเบปเบฒเบ—เบธเบเบ„เบปเบ™เบฎเบนเป‰เบ”เบตเบงเปˆเบฒเบกเบฑเบ™เบชเบดเป‰เบ™เบชเบธเบ”เบฅเบปเบ‡เปเบ™เบงเปƒเบ” ...

PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursionเป€เบšเบดเปˆเบ‡ โ€œเบšเบฑเบ™เบซเบฒเบ‚เบญเบ‡เป€เบกเบฑเบ”เบžเบทเบ”เบขเบนเปˆเปƒเบ™เบเบฐเบ”เบฒเบ™เปเบฒเบเบฎเบธเบโ€

เบœเบนเป‰เบ›เบปเบเบ„เบญเบ‡เบ‚เบญเบ‡ "เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡"

เบžเบงเบเป€เบฎเบปเบฒเบชเบฐเบซเบผเบฑเบšเบเบฑเบ™เป€เบžเบตเปˆเบกเบ•เบปเบงเบฅเบฐเบšเบธเบงเบฑเบ”เบ–เบธเบ—เบฑเบ‡เปเบปเบ”เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบžเบปเบšเบขเบนเปˆเบ•เบฒเบกเป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡เบเบฒเบ™เป€เบญเบตเป‰เบ™เบ„เบทเบ™เป€เบ‚เบปเป‰เบฒเปƒเบ™เบญเบฒเป€เบฃ, เป€เบŠเบดเปˆเบ‡เป€เบ›เบฑเบ™ โ€œเป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡โ€ เบ—เบตเปˆเป€เบ›เบฑเบ™เป€เบญเบเบฐเบฅเบฑเบเบชเบฐเป€เบžเบฒเบฐ:

WITH RECURSIVE T AS (
  SELECT
    ARRAY[id] path
  ...
UNION ALL
  SELECT
    path || id
  ...
  WHERE
    id <> ALL(T.path) -- ะฝะต ัะพะฒะฟะฐะดะฐะตั‚ ะฝะธ ั ะพะดะฝะธะผ ะธะท
)

Pro: เบ–เป‰เบฒเบกเบตเบงเบปเบ‡เบˆเบญเบ™เปƒเบ™เบ‚เปเป‰เบกเบนเบ™, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบšเปเปˆเบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เบšเบฑเบ™เบ—เบถเบเบ”เบฝเบงเบเบฑเบ™เบŠเป‰เปเบฒเบŠเป‰เบญเบ™เบขเบนเปˆเปƒเบ™เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡เบ”เบฝเบงเบเบฑเบ™.
cons: เปเบ•เปˆเปƒเบ™เป€เบงเบฅเบฒเบ”เบฝเบงเบเบฑเบ™, เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ” bypass เบšเบฑเบ™เบ—เบถเบเบ—เบฑเบ‡เบซเบกเบปเบ”เบขเปˆเบฒเบ‡เปเบ—เป‰เบˆเบดเบ‡เป‚เบ”เบเบšเปเปˆเบกเบตเบเบฒเบ™เป€เบฎเบฑเบ”เบŠเป‰เปเบฒเบ•เบปเบงเป€เบฎเบปเบฒเป€เบญเบ‡.

PostgreSQL Antipatterns: "Infinity เบšเปเปˆเปเบกเปˆเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”!", เบซเบผเบทเป€เบฅเบฑเบเบ™เป‰เบญเบเบเปˆเบฝเบงเบเบฑเบš recursionเป€เบšเบดเปˆเบ‡ "เบšเบฑเบ™เบซเบฒเบเบฒเบ™เป€เบ„เบทเปˆเบญเบ™เบเป‰เบฒเบเบ‚เบญเบ‡ Knight"

เบˆเบณเบเบฑเบ”เบ„เบงเบฒเบกเบเบฒเบงเบ‚เบญเบ‡เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡

เป€เบžเบทเปˆเบญเบซเบผเบตเบเบฅเป‰เบฝเบ‡เบชเบฐเบ–เบฒเบ™เบฐเบเบฒเบ™เบ‚เบญเบ‡ recursion "wandering" เบขเบนเปˆเปƒเบ™เบ„เบงเบฒเบกเป€เบฅเบดเบเบ—เบตเปˆเบšเปเปˆเบชเบฒเบกเบฒเบ”เป€เบ‚เบปเป‰เบฒเปƒเบˆเป„เบ”เป‰, เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบชเบปเบกเบ—เบปเบšเบชเบญเบ‡เบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเปˆเบœเปˆเบฒเบ™เบกเบฒ. เบซเบผเบท, เบ–เป‰เบฒเบžเบงเบเป€เบฎเบปเบฒเบšเปเปˆเบ•เป‰เบญเบ‡เบเบฒเบ™เบชเบฐเบซเบ™เบฑเบšเบชเบฐเบซเบ™เบนเบ™เบŠเปˆเบญเบ‡เบ‚เปเป‰เบกเบนเบ™เบ—เบตเปˆเบšเปเปˆเบˆเปเบฒเป€เบ›เบฑเบ™, เป€เบชเบตเบกเป€เบ‡เบทเปˆเบญเบ™เป„เบ‚เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบชเบทเบšเบ•เปเปˆ recursion เบ”เป‰เบงเบเบเบฒเบ™เบ„เบฒเบ”เบ„เบฐเป€เบ™เบ‚เบญเบ‡เบ„เบงเบฒเบกเบเบฒเบงเบ‚เบญเบ‡เป€เบชเบฑเป‰เบ™เบ—เบฒเบ‡:

WITH RECURSIVE T AS (
  SELECT
    ARRAY[id] path
  ...
UNION ALL
  SELECT
    path || id
  ...
  WHERE
    id <> ALL(T.path) AND
    array_length(T.path, 1) < 10
)

เป€เบฅเบทเบญเบเบงเบดเบ—เบตเบเบฒเบ™เป€เบžเบทเปˆเบญเบฅเบปเบ”เบŠเบฒเบ”เบ‚เบญเบ‡เบ—เปˆเบฒเบ™!

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: www.habr.com

เป€เบžเบตเปˆเบกเบ„เบงเบฒเบกเบ„เบดเบ”เป€เบซเบฑเบ™