PostgreSQL Antipatterns: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ

рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ - рдПрдХ рдзреЗрд░реИ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╕рдВрдпрдиреНрддреНрд░ рдпрджрд┐ рд╕рдорд╛рди "рдЧрд╣рд┐рд░реЛ" рдХрд╛рд░реНрдпрд╣рд░реВ рд╕рдореНрдмрдиреНрдзрд┐рдд рдбреЗрдЯрд╛рдорд╛ рдкреНрд░рджрд░реНрд╢рди рдЧрд░рд┐рдиреНрдЫред рддрд░ рдЕрдирд┐рдпрдиреНрддреНрд░рд┐рдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдПрдХ рджреБрд╖реНрдЯ рд╣реЛ рдЬрд╕рд▓реЗ рдХреБрдиреИ рдкрдирд┐ рдирд┐рдореНрддреНрдпрд╛рдЙрди рд╕рдХреНрдЫ рдЕрдиреНрддрд╣реАрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рдХреНрд░рд┐рдпрд╛, рд╡рд╛ (рдЬреЛ рдзреЗрд░реИ рдкрдЯрдХ рд╣реБрдиреНрдЫ) рдорд╛ "рдЦрд╛рдиреЗ" рд╕рдмреИ рдЙрдкрд▓рдмреНрдз рдореЗрдореЛрд░реА.

PostgreSQL Antipatterns: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ
рдпрд╕ рд╕рдореНрдмрдиреНрдзрдорд╛ DBMS рд▓реЗ рд╕рдорд╛рди рд╕рд┐рджреНрдзрд╛рдиреНрддрд╣рд░реВрдорд╛ рдХрд╛рдо рдЧрд░реНрджрдЫ - "рддрд┐рдиреАрд╣рд░реВрд▓реЗ рдорд▓рд╛рдИ рдЦрдиреНрди рднрдиреЗ, рддреНрдпрд╕реИрд▓реЗ рдореИрд▓реЗ рдЦрдиреНрдиреЗ"ред рддрдкрд╛рдИрдВрдХреЛ рдЕрдиреБрд░реЛрдзрд▓реЗ рдЫрд┐рдореЗрдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛рд╣рд░реВ рдорд╛рддреНрд░ рдврд┐рд▓реЛ рдЧрд░реНрди рд╕рдХреНрджреИрди, рдирд┐рд░рдиреНрддрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реНрд░реЛрддрд╣рд░реВ рд▓рд┐рдиреНрдЫ, рддрд░ рд╕рдореНрдкреВрд░реНрдг рдбрд╛рдЯрд╛рдмреЗрд╕рд▓рд╛рдИ "рдбреНрд░рдк" рдЧрд░реНрди рд╕рдХреНрдЫ, рд╕рдмреИ рдЙрдкрд▓рдмреНрдз рдореЗрдореЛрд░реА "рдЦрд╛рдиреЗ"ред рдЕрдирдиреНрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд╡рд┐рд░реБрджреНрдз рд╕реБрд░рдХреНрд╖рд╛ - рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛ рдЖрдлреИрдВрдХреЛ рдЬрд┐рдореНрдореЗрд╡рд╛рд░реАред

PostgreSQL рдорд╛, рдорд╛рд░реНрдлрдд рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрдирд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдХреНрд╖рдорддрд╛ WITH RECURSIVE рд╕рдВрд╕реНрдХрд░рдг 8.4 рдХреЛ рдЕрдирд╛рджрд┐рдХрд╛рд▓рдорд╛ рджреЗрдЦрд╛ рдкрд░реНтАНрдпреЛ, рддрд░ рддрдкрд╛рдИрд▓реЗ рдЕрдЭреИ рдкрдирд┐ рд╕рдореНрднрд╛рд╡рд┐рдд рд░реВрдкрдорд╛ рдХрдордЬреЛрд░ "рд░рдХреНрд╖рд╛рд╡рд┐рд╣реАрди" рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд╕рд╛рдордирд╛ рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫред рдпрд╕реНрддреЛ рд╕рдорд╕реНрдпрд╛рдмрд╛рдЯ рдХрд╕рд░реА рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдЙрдиреЗ ?

рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрдирд╣рд░реВ рдирд▓реЗрдЦреНрдиреБрд╣реЛрд╕реН

рд░ рдЧреИрд░-рдкреБрдирд░рд╛рд╡рд░реНрддреА рд▓реЗрдЦреНрдиреБрд╣реЛрд╕реНред рднрд╡рджреАрдп, рддрдкрд╛рдИрдХреЛ K.O.

рд╡рд╛рд╕реНрддрд╡рдорд╛, PostgreSQL рд▓реЗ рддрдкрд╛рдИрд▓реЗ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рд╕рдХреНрдиреЗ рдзреЗрд░реИ рдкреНрд░рдХрд╛рд░реНрдпрддрд╛ рдкреНрд░рджрд╛рди рдЧрд░реНрджрдЫ рдЫреИрди рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд▓рд╛рдЧреВ рдЧрд░реНрдиреБрд╣реЛрд╕реНред

рд╕рдорд╕реНрдпрд╛рдХреЛ рд▓рд╛рдЧрд┐ рдореМрд▓рд┐рдХ рд░реВрдкрдорд╛ рдлрд░рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН

рдХрд╣рд┐рд▓реЗрдХрд╛рд╣реАрдБ рддрдкрд╛рдИрд▓реЗ рд╕рдорд╕реНрдпрд╛рд▓рд╛рдИ "рднрд┐рдиреНрди рдкрдХреНрд╖" рдмрд╛рдЯ рд╣реЗрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫред рдореИрд▓реЗ рд▓реЗрдЦрдорд╛ рдпрд╕реНрддреЛ рдЕрд╡рд╕реНрдерд╛рдХреЛ рдЙрджрд╛рд╣рд░рдг рджрд┐рдПрдБ "SQL HowTo: 1000 and one way of aggregation" - рдЕрдиреБрдХреВрд▓рди рд╕рдордЧреНрд░ рдкреНрд░рдХрд╛рд░реНрдпрд╣рд░реВ рдкреНрд░рдпреЛрдЧ рдирдЧрд░реА рд╕рдВрдЦреНрдпрд╛рд╣рд░реВрдХреЛ рд╕реЗрдЯрдХреЛ рдЧреБрдгрди:

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;

loops рдХреЛ рд╕рдЯреНрдЯрд╛ generate_series рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН

рдорд╛рдиреМрдВ рд╣рд╛рдореА рд╕реНрдЯреНрд░рд┐рдЩрдХрд╛ рд▓рд╛рдЧрд┐ рд╕рдмреИ рд╕рдореНрднрд╛рд╡рд┐рдд рдЙрдкрд╕рд░реНрдЧрд╣рд░реВ рдЙрддреНрдкрдиреНрди рдЧрд░реНрдиреЗ рдХрд╛рд░реНрдпрдХреЛ рд╕рд╛рдордирд╛ рдЧрд░рд┐рд░рд╣реЗрдХрд╛ рдЫреМрдВ '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;

рдХреЗ рддрдкрд╛рдЗрдБ рдирд┐рд╢реНрдЪрд┐рдд рд╣реБрдиреБрд╣реБрдиреНрдЫ рдХрд┐ рддрдкрд╛рдЗрдБ рдпрд╣рд╛рдБ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЪрд╛рд╣рд┐рдиреНрдЫ?... рдпрджрд┐ рддрдкрд╛рдЗрдБ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реБрдиреНрдЫ рднрдиреЗ 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: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ
рдард┐рдХ рдЫ, рдПрдЙрдЯрд╛ рд╢реАрд░реНрд╖рдХрдорд╛ рд╕рдмреИ рд╕рдиреНрджреЗрд╢рд╣рд░реВ рдбрд╛рдЙрдирд▓реЛрдб рдЧрд░реНрдирдХреЛ рд▓рд╛рдЧрд┐ рд╕рд╛рдорд╛рдиреНрдп рдЕрдиреБрд░реЛрдз рдпрд╕реНрддреЛ рджреЗрдЦрд┐рдиреНрдЫ:

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;

рддрд░ рд╣рд╛рдореАрд▓рд╛рдИ рдЬрд╣рд┐рд▓реЗ рдкрдирд┐ рдореВрд▓ рд╕рдиреНрджреЗрд╢рдмрд╛рдЯ рд╕рдореНрдкреВрд░реНрдг рд╡рд┐рд╖рдп рдЪрд╛рд╣рд┐рдиреНрдЫ, рддреНрдпрд╕реЛрднрдП рд╣рд╛рдореА рдХрд┐рди рдЧрд░реНрджреИрдиреМрдВ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдорд╛ рдпрд╕рдХреЛ рдЖрдИрдбреА рдердкреНрдиреБрд╣реЛрд╕реН рд╕реНрд╡рдЪрд╛рд▓рд┐рдд?

-- ╨┤╨╛╨▒╨░╨▓╨╕╨╝ ╨┐╨╛╨╗╨╡ ╤Б ╨╛╨▒╤Й╨╕╨╝ ╨╕╨┤╨╡╨╜╤В╨╕╤Д╨╕╨║╨░╤В╨╛╤А╨╛╨╝ ╤В╨╡╨╝╤Л ╨╕ ╨╕╨╜╨┤╨╡╨║╤Б ╨╜╨░ ╨╜╨╡╨│╨╛
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: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ
рдЕрдм рд╣рд╛рдореНрд░реЛ рд╕рдореНрдкреВрд░реНрдг рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХреНрд╡реЗрд░реАрд▓рд╛рдИ рдпреЛ рдорд╛рддреНрд░рдорд╛ рдХрдо рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ:

SELECT
  *
FROM
  message
WHERE
  theme_id = $1;

рд▓рд╛рдЧреВ "рд╕реАрдорд╛рд╣рд░реВ" рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН

рдпрджрд┐ рд╣рд╛рдореА рдХреБрдиреИ рдХрд╛рд░рдгрд▓реЗ рдбрд╛рдЯрд╛рдмреЗрд╕рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдкрд░рд┐рд╡рд░реНрддрди рдЧрд░реНрди рдЕрд╕рдорд░реНрде рдЫреМрдВ рднрдиреЗ, рд╣рд╛рдореА рдХреЗрдорд╛ рднрд░ рдкрд░реНрди рд╕рдХреНрдЫреМрдВ рднрдиреЗрд░ рд╣реЗрд░реМрдВ рддрд╛рдХрд┐ рдбрд╛рдЯрд╛рдорд╛ рддреНрд░реБрдЯрд┐рдХреЛ рдЙрдкрд╕реНрдерд┐рддрд┐рд▓реЗ рдкрдирд┐ рдЕрдирдиреНрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдиреЗрддреГрддреНрд╡ рдЧрд░реНрджреИрдиред

рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЧрд╣рд┐рд░рд╛рдИ рдХрд╛рдЙрдиреНрдЯрд░

рд╣рд╛рдореА рдкреНрд░рддреНрдпреЗрдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЪрд░рдгрдорд╛ рдПрдХрд▓реЗ рдХрд╛рдЙрдиреНрдЯрд░ рдмрдврд╛рдЙрдБрдЫреМрдВ рдЬрдмрд╕рдореНрдо рд╣рд╛рдореА рд╕реНрдкрд╖реНрдЯ рд░реВрдкрдорд╛ рдЕрдкрд░реНрдпрд╛рдкреНрдд рдорд╛рдиреНрдиреЗ рд╕реАрдорд╛рдорд╛ рдкреБрдЧреНрджреИрдиреМрдВ:

WITH RECURSIVE T AS (
  SELECT
    0 i
  ...
UNION ALL
  SELECT
    i + 1
  ...
  WHERE
    T.i < 64 -- ╨┐╤А╨╡╨┤╨╡╨╗
)

рдкреНрд░реЛ: рдЬрдм рд╣рд╛рдореА рд▓реБрдк рдЧрд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕ рдЧрд░реНрдЫреМрдВ, рд╣рд╛рдореА рдЕрдЭреИ рдкрдирд┐ "рдЧрд╣рд┐рд░рд╛рдЗрдорд╛" рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реАрдорд╛ рднрдиреНрджрд╛ рдмрдвреА рдЧрд░реНрджреИрдиреМрдВред
рд╡рд┐рдкрдХреНрд╖: рддреНрдпрд╣рд╛рдБ рдХреБрдиреИ рдЧреНрдпрд╛рд░реЗрдиреНрдЯреА рдЫреИрди рдХрд┐ рд╣рд╛рдореАрд▓реЗ рдЙрд╣реА рд░реЗрдХрд░реНрдбрд▓рд╛рдИ рдлреЗрд░рд┐ рдкреНрд░рд╢реЛрдзрди рдЧрд░реНрдиреЗ рдЫреИрдиреМрдВ - рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, 15 рд░ 25 рдХреЛ рдЧрд╣рд┐рд░рд╛рдЗрдорд╛, рд░ рддреНрдпрд╕рдкрдЫрд┐ рдкреНрд░рддреНрдпреЗрдХ +10ред рд░ рдХрд╕реИрд▓реЗ рдкрдирд┐ "рдЪреМрдбрд╛рдИ" рдХреЛ рдмрд╛рд░реЗ рдорд╛ рдХреЗрд╣рд┐ рдкреНрд░рддрд┐рдЬреНрдЮрд╛ рдЧрд░реЗрдиред

рдФрдкрдЪрд╛рд░рд┐рдХ рд░реВрдкрдорд╛, рдпрд╕реНрддреЛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЕрд╕реАрдо рд╣реБрдиреЗрдЫреИрди, рддрд░ рдпрджрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдгрдорд╛ рд░реЗрдХрд░реНрдбрд╣рд░реВрдХреЛ рд╕рдВрдЦреНрдпрд╛ рджреНрд░реБрдд рд░реВрдкрдорд╛ рдмрдвреНрдЫ, рд╣рд╛рдореА рд╕рдмреИрд▓рд╛рдИ рд░рд╛рдореНрд░рд░реА рдерд╛рд╣рд╛ рдЫ рдХрд┐ рдпреЛ рдХрд╕рд░реА рд╕рдорд╛рдкреНрдд рд╣реБрдиреНрдЫ ...

PostgreSQL Antipatterns: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ"рдЪреЗрд╕рдмреЛрд░реНрдбрдорд╛ рдЕрдирд╛рдЬрдХреЛ рд╕рдорд╕реНрдпрд╛" рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН

"рдорд╛рд░реНрдЧ" рдХреЛ рд╕рдВрд░рдХреНрд╖рдХ

рд╣рд╛рдореА рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдкрдорд╛ рдПрд░реЗрдорд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдорд╛рд░реНрдЧрдорд╛ рд╕рд╛рдордирд╛ рдЧрд░реЗрдХрд╛ рд╕рдмреИ рд╡рд╕реНрддреБ рдкрд╣рд┐рдЪрд╛рдирдХрд░реНрддрд╛рд╣рд░реВ рдердкреНрдЫреМрдВ, рдЬреБрди рдпрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп "рдорд╛рд░реНрдЧ" рд╣реЛ:

WITH RECURSIVE T AS (
  SELECT
    ARRAY[id] path
  ...
UNION ALL
  SELECT
    path || id
  ...
  WHERE
    id <> ALL(T.path) -- ╨╜╨╡ ╤Б╨╛╨▓╨┐╨░╨┤╨░╨╡╤В ╨╜╨╕ ╤Б ╨╛╨┤╨╜╨╕╨╝ ╨╕╨╖
)

рдкреНрд░реЛ: рдпрджрд┐ рдбреЗрдЯрд╛рдорд╛ рдПрдХ рдЪрдХреНрд░ рдЫ рднрдиреЗ, рд╣рд╛рдореА рдмрд┐рд▓реНрдХреБрд▓ рдПрдЙрдЯреИ рд░реЗрдХрд░реНрдбрд▓рд╛рдИ рдПрдЙрдЯреИ рдорд╛рд░реНрдЧ рднрд┐рддреНрд░ рдмрд╛рд░рдореНрдмрд╛рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЧрд░реНрджреИрдиреМрдВред
рд╡рд┐рдкрдХреНрд╖: рддрд░ рдПрдХреИ рд╕рдордпрдорд╛, рд╣рд╛рдореА рд╢рд╛рдмреНрджрд┐рдХ рд░реВрдкрдорд╛ рдЖрдлреИрд▓рд╛рдИ рджреЛрд╣реЛрд░реНрдпрд╛рдЙрди рдмрд┐рдирд╛ рд╕рдмреИ рд░реЗрдХрд░реНрдбрд╣рд░реВ рдмрд╛рдЗрдкрд╛рд╕ рдЧрд░реНрди рд╕рдХреНрдЫреМрдВред

PostgreSQL Antipatterns: "рдЗрдиреНрдлрд┐рдирд┐рдЯреА рд╕реАрдорд╛ рд╣реЛрдЗрди!", рд╡рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИ"рдирд╛рдЗрдЯрдХреЛ рдЪрд╛рд▓ рд╕рдорд╕реНрдпрд╛" рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН

рдкрде рд▓рдореНрдмрд╛рдЗ рд╕реАрдорд╛

рдмреБрдЭреНрди рдирд╕рдХрд┐рдиреЗ рдЧрд╣рд┐рд░рд╛рдЗрдорд╛ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ "рднрдЯрдХ" рдХреЛ рд╕реНрдерд┐рддрд┐рдмрд╛рдЯ рдмрдЪреНрди, рд╣рд╛рдореА рджреБрдИ рдЕрдШрд┐рд▓реНрд▓реЛ рд╡рд┐рдзрд┐рд╣рд░реВ рд╕рдВрдпреЛрдЬрди рдЧрд░реНрди рд╕рдХреНрдЫреМрдВред рд╡рд╛, рдпрджрд┐ рд╣рд╛рдореА рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреНрд╖реЗрддреНрд░рд╣рд░реВрд▓рд╛рдИ рд╕рдорд░реНрдерди рдЧрд░реНрди рдЪрд╛рд╣рдБрджреИрдиреМрдВ рднрдиреЗ, рдкрде рд▓рдореНрдмрд╛рдЗрдХреЛ рдЕрдиреБрдорд╛рдирдХреЛ рд╕рд╛рде рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЬрд╛рд░реА рд░рд╛рдЦреНрдирдХреЛ рд▓рд╛рдЧрд┐ рд╕рд░реНрддрдХреЛ рдкреВрд░реНрддрд┐ рдЧрд░реНрдиреБрд╣реЛрд╕реН:

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди