PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

αž“αŸ…αž€αŸ’αž“αž»αž„αž”αŸ’αžšαž–αŸαž“αŸ’αž’ ERP αžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰ αž’αž„αŸ’αž‚αž—αžΆαž–αž‡αžΆαž…αŸ’αžšαžΎαž“αž˜αžΆαž“αž›αž€αŸ’αžαžŽαŸˆαž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αžœαžαŸ’αžαž»αžŠαžΌαž…αž‚αŸ’αž“αžΆαžαž˜αŸ’αžšαž„αŸ‹αž‡αž½αžš αž˜αŸ‚αž€αž’αžΆαž„αž“αŸƒαž‘αŸ†αž“αžΆαž€αŸ‹αž‘αŸ†αž“αž„αžŠαžΌαž“αžαžΆ - αž€αžΌαž“αž…αŸ… - αž“αŸαŸ‡αž‚αžΊαž‡αžΆαžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž’αž„αŸ’αž‚αž—αžΆαž–αžšαž”αžŸαŸ‹αžŸαž αž‚αŸ’αžšαžΆαžŸ (សអខអ αž“αžΆαž™αž€αžŠαŸ’αž‹αžΆαž“ αž“αž·αž„αž€αŸ’αžšαž»αž˜αž€αžΆαžšαž„αžΆαžšαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡) αž“αž·αž„αž€αžΆαžαžΆαž‘αž»αž€αž‘αŸ†αž“αž·αž‰ αž“αž·αž„αžαŸ†αž”αž“αŸ‹αž€αžΆαžšαž„αžΆαžš αž“αž·αž„αž—αžΌαž˜αž·αžŸαžΆαžŸαŸ’αžαŸ’αžšαž“αŸƒαž…αŸ†αžŽαž»αž…αž›αž€αŸ‹...

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

αžαžΆαž˜αž€αžΆαžšαž–αž·αžαž˜αž·αž“αž˜αžΆαž“αž‘αŸαŸ” αžαŸ†αž”αž“αŸ‹αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž€αž˜αŸ’αž˜αž’αžΆαž‡αžΈαžœαž€αž˜αŸ’αž˜αžŠαŸ‚αž›αž‡αžΆαž€αž“αŸ’αž›αŸ‚αž„αžŠαŸ‚αž›αž“αžΉαž„αž˜αž·αž“αž˜αžΆαž“αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜αžŽαžΆαž˜αž½αž™αž‡αžΆαž›αž‘αŸ’αž’αž•αž›αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž‘αŸ„αŸ‡αž”αžΈαž‡αžΆαž’αŸ’αž“αž€αž˜αž·αž“αž’αŸ’αžœαžΎαž€αžΆαžš "αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžΆαž‡αžΈαžœαž€αž˜αŸ’αž˜" αž’αŸ’αž“αž€αž“αŸ…αžαŸ‚αž’αžΆαž…αž‡αž½αž”αž”αŸ’αžšαž‘αŸ‡αž‘αŸ†αž“αžΆαž€αŸ‹αž‘αŸ†αž“αž„αžαžΆαž˜αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜αž™αŸ‰αžΆαž„αž„αžΆαž™αžŸαŸ’αžšαž½αž›αŸ” αžœαžΆβ€‹αž‡αžΆβ€‹αžšαžΏαž„β€‹αž˜αž·αž“β€‹αž›αŸ’αž’β€‹αž‘αŸ αžŸαžΌαž˜αŸ’αž”αžΈβ€‹αžαŸ‚β€‹αž˜αŸ‚αž€αž’αžΆαž„β€‹αž‚αŸ’αžšαž½αžŸαžΆαžšβ€‹αžšαž”αžŸαŸ‹β€‹αž’αŸ’αž“αž€ αž¬β€‹αž•αŸ‚αž“αž€αžΆαžšβ€‹αž‡αžΆαž“αŸ‹β€‹αž“αŸ…β€‹αž€αŸ’αž“αž»αž„β€‹αž˜αž‡αŸ’αžˆαž˜αžŽαŸ’αžŒαž›β€‹αž›αž€αŸ‹αž‘αŸ†αž“αž·αž‰β€‹αž€αŸβ€‹αž˜αžΆαž“β€‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’β€‹αžŠαžΌαž…αž‚αŸ’αž“αžΆβ€‹αžŠαŸ‚αžšαŸ”

αž˜αžΆαž“αžœαž·αž’αžΈαž‡αžΆαž…αŸ’αžšαžΎαž“αž€αŸ’αž“αž»αž„αž€αžΆαžšαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžŠαžΎαž˜αžˆαžΎαž”αŸ‚αž”αž“αŸαŸ‡αž“αŸ…αž€αŸ’αž“αž»αž„ DBMS αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžαŸ’αž„αŸƒαž“αŸαŸ‡αž™αžΎαž„αž“αžΉαž„αž•αŸ’αžαŸ„αžαž›αžΎαž‡αž˜αŸ’αžšαžΎαžŸαžαŸ‚αž˜αž½αž™αž‚αžαŸ‹αŸ–

CREATE TABLE hier(
  id
    integer
      PRIMARY KEY
, pid
    integer
      REFERENCES hier
, data
    json
);

CREATE INDEX ON hier(pid); -- Π½Π΅ Π·Π°Π±Ρ‹Π²Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ FK Π½Π΅ ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π΅Ρ‚ автосозданиС индСкса, Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ PK

αž αžΎαž™αžαžŽαŸˆαž–αŸαž›αžŠαŸ‚αž›αž’αŸ’αž“αž€αž€αŸ†αž–αž»αž„αžŸαž˜αŸ’αž›αžΉαž„αž˜αžΎαž›αž‘αŸ…αž‡αž˜αŸ’αžšαŸ…αž“αŸƒαž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜ αžœαžΆαž€αŸ†αž–αž»αž„αžšαž„αŸ‹αž…αžΆαŸ†αžŠαŸ„αž™αž’αžαŸ‹αž’αŸ’αž˜αžαŸ‹ αžŠαžΎαž˜αŸ’αž”αžΈαž˜αžΎαž›αžαžΆαžαžΎαžœαž·αž’αžΈ "αž†αŸ„αžαž›αŸ’αž„αž„αŸ‹" αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž”αŸ‚αž”αž“αŸαŸ‡αž“αžΉαž„αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž™αŸ‰αžΆαž„αžŽαžΆαŸ”

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
αžŸαžΌαž˜αž€αŸ’αžšαž‘αŸαž€αž˜αžΎαž›αž”αž‰αŸ’αž αžΆαž’αž˜αŸ’αž˜αžαžΆαžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„ αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸαž“αŸ…αž€αŸ’αž“αž»αž„ SQL αž“αž·αž„αž–αŸ’αž™αžΆαž™αžΆαž˜αž€αŸ‚αž›αž˜αŸ’αž’αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸαŸ”

#1. αžαžΎαžšαž“αŸ’αž’αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“?

αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž™αžΎαž„αž™αž›αŸ‹αž…αŸ’αž”αžΆαžŸαŸ‹αžαžΆ αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž“αŸαŸ‡αž“αžΉαž„αž†αŸ’αž›αž»αŸ‡αž”αž‰αŸ’αž…αžΆαŸ†αž„αž–αžΈαž•αŸ’αž“αŸ‚αž€αžšαž„αž“αŸƒαž“αžΆαž™αž€αžŠαŸ’αž‹αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžšαž”αžŸαŸ‹αž’αž„αŸ’αž‚αž€αžΆαžšαŸ– αž“αžΆαž™αž€αžŠαŸ’αž‹αžΆαž“ αž€αžΆαžšαž”αŸ‚αž„αž…αŸ‚αž€ αžœαž·αžŸαŸαž™ សអខអ αž€αŸ’αžšαž»αž˜αž€αžΆαžšαž„αžΆαžš ... - αž’αŸ’αžœαžΈαž€αŸαžŠαŸ„αž™αžŠαŸ‚αž›αž’αŸ’αž“αž€αž αŸ…αž–αž½αž€αž‚αŸαŸ”
PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

αž‡αžΆαžŠαŸ†αž”αžΌαž„ αž…αžΌαžšαž™αžΎαž„αž”αž„αŸ’αž€αžΎαž 'ដើមឈើ' αžšαž”αžŸαŸ‹αž™αžΎαž„αž“αŸƒαž’αžΆαžαž» 10K

INSERT INTO hier
WITH RECURSIVE T AS (
  SELECT
    1::integer id
  , '{1}'::integer[] pids
UNION ALL
  SELECT
    id + 1
  , pids[1:(random() * array_length(pids, 1))::integer] || (id + 1)
  FROM
    T
  WHERE
    id < 10000
)
SELECT
  pids[array_length(pids, 1)] id
, pids[array_length(pids, 1) - 1] pid
FROM
  T;

αž…αžΌαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαŸαžŸαžΆαž˜αž‰αŸ’αž‰αž”αŸ†αž•αž»αž - αž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αž”αž»αž‚αŸ’αž‚αž›αž·αž€αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŠαŸ‚αž›αž’αŸ’αžœαžΎαž€αžΆαžšαž“αŸ…αž€αŸ’αž“αž»αž„αžœαž·αžŸαŸαž™αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™ αž¬αž“αŸ…αž€αŸ’αž“αž»αž„αž›αž€αŸ’αžαžαžŽαŸ’αžŒαž“αŸƒαž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜ - αžŸαŸ’αžœαŸ‚αž„αžšαž€αž€αžΌαž“αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒ node. αžœαžΆαž‡αžΆαž€αžΆαžšαž›αŸ’αž’αž•αž„αžŠαŸ‚αžšαž€αŸ’αž“αž»αž„αž€αžΆαžšαž‘αž‘αž½αž›αž”αžΆαž“ "αž‡αž˜αŸ’αžšαŸ…" αž“αŸƒαž€αžΌαž“αž…αŸ…... αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡αž’αžΆαž…αž‡αžΆαž€αžΆαžšαž…αžΆαŸ†αž”αžΆαž…αŸ‹ αž§αž‘αžΆαž αžšαžŽαŸ αžŠαžΎαž˜αŸ’αž”αžΈαž€αžŸαžΆαž„αž”αŸ’αžšαž—αŸαž‘αž˜αž½αž™αž…αŸ†αž“αž½αž“αŸ” αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαžŸαŸ’αž˜αž»αž‚αžŸαŸ’αž˜αžΆαž‰αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαž”αž‰αŸ’αž‡αžΈαž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž”αž»αž‚αŸ’αž‚αž›αž·αž€αž‘αžΆαŸ†αž„αž“αŸαŸ‡.

αž’αŸ’αžœαžΈαŸ—αž“αžΉαž„αž›αŸ’αž’αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž€αžΌαž“αž…αŸ…αž‘αžΆαŸ†αž„αž“αŸαŸ‡αžαŸ‚αž–αžΈαžšαž”αžΈαž€αž˜αŸ’αžšαž·αž αž αžΎαž™αž…αŸ†αž“αž½αž“αž˜αžΆαž“αž€αŸ’αž“αž»αž„αžαŸ’αž‘αž„αŸ‹αžŠαž”αŸ‹ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž›αžΎαžŸαž–αžΈ 5 αž€αž˜αŸ’αžšαž·αž αž αžΎαž™αž˜αžΆαž“αž€αžΌαž“αž…αŸ…αžšαžΆαž”αŸ‹αžŸαž·αž”αž“αžΆαž€αŸ‹αžšαž½αž…αž αžΎαž™ αžœαžΆαž’αžΆαž…αž“αžΉαž„αž˜αžΆαž“αž”αž‰αŸ’αž αžΆαŸ” αžŸαžΌαž˜αž€αŸ’αžšαž‘αŸαž€αž˜αžΎαž›αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž›αž‡αž˜αŸ’αžšαžΎαžŸαžŸαŸ’αžœαŸ‚αž„αžšαž€αžαžΆαž˜αž”αŸ‚αž”αž”αŸ’αžšαž–αŸƒαžŽαžΈαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŸαžšαžŸαŸαžš (αž“αž·αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš)αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž‡αžΆαžŠαŸ†αž”αžΌαž„ αž…αžΌαžšαž™αžΎαž„αž€αŸ†αžŽαžαŸ‹αžαžΆαžαžΎαžαŸ’αž“αžΆαŸ†αž„αžŽαžΆαžŠαŸ‚αž›αž‚αž½αžšαž±αŸ’αž™αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž”αŸ†αž•αž»αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžŸαŸ’αžšαžΆαžœαž‡αŸ’αžšαžΆαžœαžšαž”αžŸαŸ‹αž™αžΎαž„αŸ”

αž…αŸ’αžšαžΎαž“αž”αŸ†αž•αž»αžαŸ” "αž‡αŸ’αžšαŸ…" αžŠαžΎαž˜αžˆαžΎαžšαž„αŸ–

WITH RECURSIVE T AS (
  SELECT
    id
  , pid
  , ARRAY[id] path
  FROM
    hier
  WHERE
    pid IS NULL
UNION ALL
  SELECT
    hier.id
  , hier.pid
  , T.path || hier.id
  FROM
    T
  JOIN
    hier
      ON hier.pid = T.id
)
TABLE T ORDER BY array_length(path, 1) DESC;

 id  | pid  | path
---------------------------------------------
7624 | 7623 | {7615,7620,7621,7622,7623,7624}
4995 | 4994 | {4983,4985,4988,4993,4994,4995}
4991 | 4990 | {4983,4985,4988,4989,4990,4991}
...

αž…αŸ’αžšαžΎαž“αž”αŸ†αž•αž»αžαŸ” "αž’αŸ†αž‘αžΌαž›αžΆαž™" αžŠαžΎαž˜αžˆαžΎαžšαž„αŸ–

...
SELECT
  path[1] id
, count(*)
FROM
  T
GROUP BY
  1
ORDER BY
  2 DESC;

id   | count
------------
5300 |   30
 450 |   28
1239 |   27
1573 |   25

αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžšαž‘αžΆαŸ†αž„αž“αŸαŸ‡ αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž’αž˜αŸ’αž˜αžαžΆαŸ” αž…αžΌαž›αžšαž½αž˜αž‘αžΎαž„αžœαž·αž‰:
PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž‚αŸ†αžšαžΌαžŸαŸ†αžŽαžΎαž“αŸαŸ‡αŸ” αž…αŸ†αž“αž½αž“αž“αŸƒαž€αžΆαžšαž’αŸ’αžœαžΎαž˜αŸ’αžαž„αž‘αŸ€αžαž“αžΉαž„αžŠαžΌαž…αž‚αŸ’αž“αžΆαž‘αŸ…αž“αžΉαž„αž…αŸ†αž“αž½αž“αžŸαžšαž»αž”αž“αŸƒαž€αžΌαž“αž…αŸ… (αž αžΎαž™αž˜αžΆαž“αžšαžΆαž”αŸ‹αžŸαž·αž”αž“αŸƒαž–αž½αž€αž‚αŸ) αž αžΎαž™αžœαžΆαž’αžΆαž…αžαŸ’αžšαžΌαžœαž€αžΆαžšαž’αž“αž’αžΆαž“αžŸαŸ†αžαžΆαž“αŸ‹αŸ— αž αžΎαž™αž‡αžΆαž›αž‘αŸ’αž’αž•αž› αž–αŸαž›αžœαŸαž›αžΆαŸ”

αžαŸ„αŸ‡αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž˜αŸ‚αž€αž’αžΆαž„ "αž’αŸ†αž‘αžΌαž›αžΆαž™αž”αŸ†αž•αž»αž"αŸ–

WITH RECURSIVE T AS (
  SELECT
    id
  FROM
    hier
  WHERE
    id = 5300
UNION ALL
  SELECT
    hier.id
  FROM
    T
  JOIN
    hier
      ON hier.pid = T.id
)
TABLE T;

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αžŠαžΌαž…αžŠαŸ‚αž›αž”αžΆαž“αžšαŸ†αž–αžΉαž„αž‘αž»αž€ αž™αžΎαž„αž”αžΆαž“αžšαž€αžƒαžΎαž‰αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž…αŸ†αž“αž½αž“ 30 αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž–αž½αž€αž‚αŸαž”αžΆαž“αž…αŸ†αžŽαžΆαž™ 60% αž“αŸƒαž–αŸαž›αžœαŸαž›αžΆαžŸαžšαž»αž”αž›αžΎαž”αž‰αŸ’αž αžΆαž“αŸαŸ‡ - αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚αž–αž½αž€αž‚αŸαž€αŸαž”αžΆαž“αž’αŸ’αžœαžΎαž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αž…αŸ†αž“αž½αž“ 30 αž“αŸ…αž€αŸ’αž“αž»αž„αž›αž·αž”αž·αž€αŸ’αžšαž˜αž•αž„αžŠαŸ‚αžšαŸ” αžαžΎαž’αžΆαž…αž’αŸ’αžœαžΎαž”αžΆαž“αžαž·αž…αž‘αŸ?

αž€αžΆαžšβ€‹αž’αžΆαž“β€‹αž—αžŸαŸ’αžαž»αžαžΆαž„β€‹αž…αŸ’αžšαžΎαž“β€‹αžαžΆαž˜β€‹αž›αž·αž”αž·αž€αŸ’αžšαž˜

αžαžΎαž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αž„αŸ’αž€αžΎαžαžŸαŸ†αžŽαž½αžšαž›αž·αž”αž·αž€αŸ’αžšαž˜αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ’αž“αžΆαŸ†αž„αž“αžΈαž˜αž½αž™αŸ—αž‘αŸ? αžœαžΆαž”αŸ’αžšαŸ‚αžαžΆαž‘αŸ - αž™αžΎαž„αž’αžΆαž…αž’αžΆαž“αž–αžΈαž›αž·αž”αž·αž€αŸ’αžšαž˜ αžŠαŸ„αž™αž”αŸ’αžšαžΎαž‚αŸ’αžšαžΆαž”αŸ‹αž…αž»αž…αž‡αžΆαž…αŸ’αžšαžΎαž“αž€αŸ’αž“αž»αž„αž–αŸαž›αžαŸ‚αž˜αž½αž™αž€αŸ’αž“αž»αž„αž€αžΆαžšαž αŸ…αž˜αž½αž™αŸ” αžŠαŸ„αž™αž˜αžΆαž“αž‡αŸ†αž“αž½αž™ = ANY(array).

αž αžΎαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž€αŸ’αžšαž»αž˜αž“αžΈαž˜αž½αž™αŸ—αž“αŸƒαž’αŸ’αž“αž€αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαž”αŸ‚αž”αž“αŸαŸ‡ αž™αžΎαž„αž’αžΆαž…αž™αž€αž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŠαŸ‚αž›αž”αžΆαž“αžšαž€αžƒαžΎαž‰αž“αŸ…αž€αŸ’αž“αž»αž„αž‡αŸ†αž αžΆαž“αž˜αž»αž“αžŠαŸ„αž™ "αžαŸ’αž“αžΆαŸ†αž„" αŸ” αž“αŸ„αŸ‡αž‚αžΊαž“αŸ…αž‡αŸ†αž αžΆαž“αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž“αžΈαž˜αž½αž™αŸ—αž™αžΎαž„αž“αžΉαž„ αžŸαŸ’αžœαŸ‚αž„αžšαž€αž€αžΌαž“αž…αŸ…αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒαž€αž˜αŸ’αžšαž·αžαž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αž˜αž½αž™αž€αŸ’αž“αž»αž„αž–αŸαž›αžαŸ‚αž˜αž½αž™.

αž˜αžΆαž“αžαŸ‚, αž“αŸ…αž‘αžΈαž“αŸαŸ‡αž‡αžΆαž”αž‰αŸ’αž αžΆ, αž€αŸ’αž“αž»αž„β€‹αž€αžΆαžšβ€‹αž‡αŸ’αžšαžΎαžŸβ€‹αžšαžΎαžŸβ€‹αžŠαžŠαŸ‚αž›αŸ— αž’αŸ’αž“αž€β€‹αž˜αž·αž“β€‹αž’αžΆαž…β€‹αž…αžΌαž›β€‹αžŠαŸ†αžŽαžΎαžšβ€‹αž€αžΆαžšβ€‹αžŠαŸ„αž™β€‹αžαŸ’αž›αž½αž“β€‹αžœαžΆβ€‹αž€αŸ’αž“αž»αž„β€‹αžŸαŸ†αžŽαž½αžšβ€‹αžŠαŸ‚αž›β€‹αž”αžΆαž“β€‹αžŠαžΆαž€αŸ‹β€‹αž”αž‰αŸ’αž…αžΌαž›β€‹αž‚αŸ’αž“αžΆβ€‹αž”αžΆαž“β€‹αž‘αŸαŸ”αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž™αžΎαž„αžαŸ’αžšαžΌαžœαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαžŠαžΌαž…αž˜αŸ’αžŠαŸαž…αžŠαŸ‚αž›αž”αžΆαž“αžšαž€αžƒαžΎαž‰αž“αŸ…αž€αž˜αŸ’αžšαž·αžαž˜αž»αž“... αžœαžΆαž”αŸ’αžšαŸ‚αžαžΆαžœαžΆαž˜αž·αž“αž’αžΆαž…αž‘αŸ…αžšαž½αž…αž‘αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαžŸαŸ†αžŽαž½αžšαžŠαŸ‚αž›αž”αžΆαž“αžŠαžΆαž€αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž‘αžΆαŸ†αž„αž˜αžΌαž› αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžœαžΆαž›αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αžšαž”αžŸαŸ‹αžœαžΆαžœαžΆαž’αžΆαž…αž‘αŸ…αžšαž½αž…αŸ” αž αžΎαž™αžœαžΆαž›αž“αŸαŸ‡αž€αŸαž’αžΆαž…αž‡αžΆαž’αžΆαžšαŸ - αžŠαŸ‚αž›αž‡αžΆαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž™αžΎαž„αžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΎ ANY.

αžœαžΆαžŸαŸ’αžαžΆαž”αŸ‹αž‘αŸ…αžŠαžΌαž…αž‡αžΆαž†αŸ’αž€αž½αžαž”αž“αŸ’αžαž·αž… αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž“αŸ…αž€αŸ’αž“αž»αž„αžŠαŸ’αž™αžΆαž€αŸ’αžšαžΆαž˜αž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„αž‚αžΊαžŸαžΆαž˜αž‰αŸ’αž‰αŸ”

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

WITH RECURSIVE T AS (
  SELECT
    ARRAY[id] id$
  FROM
    hier
  WHERE
    id = 5300
UNION ALL
  SELECT
    ARRAY(
      SELECT
        id
      FROM
        hier
      WHERE
        pid = ANY(T.id$)
    ) id$
  FROM
    T
  WHERE
    coalesce(id$, '{}') <> '{}' -- условиС Π²Ρ‹Ρ…ΠΎΠ΄Π° ΠΈΠ· Ρ†ΠΈΠΊΠ»Π° - пустой массив
)
SELECT
  unnest(id$) id
FROM
  T;

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž αžΎαž™αž“αŸ…αž‘αžΈαž“αŸαŸ‡αž’αŸ’αžœαžΈαžŠαŸ‚αž›αžŸαŸ†αžαžΆαž“αŸ‹αž”αŸ†αž•αž»αžαž‚αžΊαž˜αž·αž“αžŸαžΌαž˜αŸ’αž”αžΈαžαŸ‚ αžˆαŸ’αž“αŸ‡ 1.5 αžŠαž„αž αžΎαž™β€‹αžαžΆβ€‹αž™αžΎαž„β€‹αžŠαž€β€‹αžŸαžαž·αž”αžŽαŸ’αžŠαŸ„αŸ‡β€‹αž’αžΆαžŸαž“αŸ’αž“β€‹αžαž·αž…β€‹αž‡αžΆαž„ αž–αŸ’αžšαŸ„αŸ‡β€‹αž™αžΎαž„β€‹αž˜αžΆαž“β€‹αž€αžΆαžšβ€‹αž αŸ…β€‹αž‘αŸ…β€‹αž›αž·αž”αž·αž€αŸ’αžšαž˜β€‹αžαŸ‚ 5 αžŠαž„β€‹αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡β€‹αž‡αŸ†αž“αž½αžŸβ€‹αž±αŸ’αž™ 30!

αž”αŸ’αžšαžΆαž€αŸ‹αžšαž„αŸ’αžœαžΆαž“αŸ‹αž”αž“αŸ’αžαŸ‚αž˜αž‚αžΊαž‡αžΆαž€αžΆαžšαž–αž·αžαžŠαŸ‚αž›αžαžΆαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž€αžΆαžš unnest αž…αž»αž„αž€αŸ’αžšαŸ„αž™ αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαž“αžΉαž„αž“αŸ…αžαŸ‚αž”αž‰αŸ’αž‡αžΆαžŠαŸ„αž™ "αž€αž˜αŸ’αžšαž·αž" αŸ”

αžŸαž‰αŸ’αž‰αžΆαžαŸ’αž“αžΆαŸ†αž„

αž€αžΆαžšαž–αž·αž…αžΆαžšαžŽαžΆαž”αž“αŸ’αž‘αžΆαž”αŸ‹αžŠαŸ‚αž›αž“αžΉαž„αž‡αž½αž™αž€αŸ‚αž›αž˜αŸ’αž’αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž‚αžΊ βˆ’ "αžŸαŸ’αž›αžΉαž€" αž˜αž·αž“αž’αžΆαž…αž˜αžΆαž“αž€αžΌαž“αž”αžΆαž“αž‘αŸαŸ”αž“αŸ„αŸ‡αž‚αžΊαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž–αž½αž€αž‚αŸαž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž˜αžΎαž› "αž…αž»αŸ‡αž€αŸ’αžšαŸ„αž˜" αž‘αžΆαž›αŸ‹αžαŸ‚αžŸαŸ„αŸ‡αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž—αžΆαžšαž€αž·αž…αŸ’αž…αžšαž”αžŸαŸ‹αž™αžΎαž„ αž“αŸαŸ‡αž˜αžΆαž“αž“αŸαž™αžαžΆ αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž™αžΎαž„αž’αŸ’αžœαžΎαžαžΆαž˜αžαŸ’αžŸαŸ‚αžŸαž„αŸ’αžœαžΆαž€αŸ‹αž“αŸƒαž“αžΆαž™αž€αžŠαŸ’αž‹αžΆαž“ αž αžΎαž™αžˆαžΆαž“αžŠαž›αŸ‹αž”αž»αž‚αŸ’αž‚αž›αž·αž€ αž“αŸ„αŸ‡αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αžšαž€αž˜αžΎαž›αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαžαžΆαž˜αžŸαžΆαžαžΆαž“αŸαŸ‡αž‘αŸαŸ”

αžαŸ„αŸ‡αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„αžαžΆαžšαžΆαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αŸ” αž”αž“αŸ’αžαŸ‚αž˜ boolean- αžœαžΆαž›αžŠαŸ‚αž›αž“αžΉαž„αž”αŸ’αžšαžΆαž”αŸ‹αž™αžΎαž„αž—αŸ’αž›αžΆαž˜αŸ—αžαžΆαžαžΎαž’αžΆαžαž»αž–αž·αžŸαŸαžŸαž“αŸαŸ‡αž“αŸ…αž€αŸ’αž“αž»αž„αž˜αŸ‚αž€αž’αžΆαž„αžšαž”αžŸαŸ‹αž™αžΎαž„αž‚αžΊαž‡αžΆ "αžαŸ’αž“αžΆαŸ†αž„" - αž“αŸ„αŸ‡αž‚αžΊαžαžΆαžαžΎαžœαžΆαž’αžΆαž…αž˜αžΆαž“αž€αžΌαž“αž…αŸ…αž”αžΆαž“αžŠαŸ‚αžšαž¬αž‘αŸαŸ”

ALTER TABLE hier
  ADD COLUMN branch boolean;

UPDATE
  hier T
SET
  branch = TRUE
WHERE
  EXISTS(
    SELECT
      NULL
    FROM
      hier
    WHERE
      pid = T.id
    LIMIT 1
);
-- Запрос ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½: 3033 строк ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΎ Π·Π° 42 мс.

αž’αžŸαŸ’αž…αžΆαžšαŸ’αž™! αžœαžΆαž”αŸ’αžšαŸ‚αžαžΆαž˜αžΆαž“αžαŸ‚αž‡αžΆαž„ 30% αž“αŸƒαž’αžΆαžαž»αžŠαžΎαž˜αžˆαžΎαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŠαŸ‚αž›αž˜αžΆαž“αž€αžΌαž“αž…αŸ…αŸ”

αž₯αž‘αžΌαžœαž“αŸαŸ‡αžŸαžΌαž˜αž”αŸ’αžšαžΎαž˜αŸαž€αžΆαž“αž·αž…αžαž»αžŸαž‚αŸ’αž“αžΆαž”αž“αŸ’αžαž·αž…αž”αž“αŸ’αžαž½αž… - αž€αžΆαžšαžαž—αŸ’αž‡αžΆαž”αŸ‹αž‘αŸ…αž•αŸ’αž“αŸ‚αž€αžŠαŸ‚αž›αž”αž„αŸ’αž€αžΎαžαž‘αžΎαž„αžœαž·αž‰αžαžΆαž˜αžšαž™αŸˆ LATERALαžŠαŸ‚αž›αž“αžΉαž„αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž™αžΎαž„αž…αžΌαž›αž‘αŸ…αž€αžΆαž“αŸ‹αžœαžΆαž›αž“αŸƒ "αžαžΆαžšαžΆαž„" αžŠαŸ‚αž›αž”αŸ’αžšαžΎαž‘αžΎαž„αžœαž·αž‰αž—αŸ’αž›αžΆαž˜αŸ— αž αžΎαž™αž”αŸ’αžšαžΎαž˜αž»αžαž„αžΆαžšαžŸαžšαž»αž”αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž›αž€αŸ’αžαžαžŽαŸ’αžŒαžαž˜αŸ’αžšαž„αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαžαŸ’αž“αžΆαŸ†αž„αžŠαžΎαž˜αŸ’αž”αžΈαž€αžΆαžαŸ‹αž”αž“αŸ’αžαž™αžŸαŸ†αžŽαž»αŸ†αž“αŸƒαž‚αŸ’αžšαžΆαž”αŸ‹αž…αž»αž…αŸ–

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜

WITH RECURSIVE T AS (
  SELECT
    array_agg(id) id$
  , array_agg(id) FILTER(WHERE branch) ns$
  FROM
    hier
  WHERE
    id = 5300
UNION ALL
  SELECT
    X.*
  FROM
    T
  JOIN LATERAL (
    SELECT
      array_agg(id) id$
    , array_agg(id) FILTER(WHERE branch) ns$
    FROM
      hier
    WHERE
      pid = ANY(T.ns$)
  ) X
    ON coalesce(T.ns$, '{}') <> '{}'
)
SELECT
  unnest(id$) id
FROM
  T;

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž™αžΎαž„β€‹αž’αžΆαž…β€‹αž€αžΆαžαŸ‹β€‹αž”αž“αŸ’αžαž™β€‹αž€αžΆαžšβ€‹αž αŸ…β€‹αžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸβ€‹αž˜αž½αž™β€‹αž‘αŸ€αžβ€‹αž αžΎαž™β€‹ αž”αžΆαž“αžˆαŸ’αž“αŸ‡αž…αŸ’αžšαžΎαž“αž‡αžΆαž„ 2 αžŠαž„αž€αŸ’αž“αž»αž„αž”αžšαž·αž˜αžΆαžŽ αž’αžΆαž“αž‘αžΎαž„αžœαž·αž‰αŸ”

#្. αž…αžΌαžšαž™αžΎαž„αžαŸ’αžšαž›αž”αŸ‹αž‘αŸ…αž«αžŸ

αž€αŸ’αž”αž½αž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž“αŸαŸ‡αž“αžΉαž„αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αžΆαžšαž”αŸ’αžšαž˜αžΌαž›αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžΆαžαž»αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ "αž‘αžΎαž„αž›αžΎαžŠαžΎαž˜αžˆαžΎ" αžαžŽαŸˆαž–αŸαž›αžŠαŸ‚αž›αžšαž€αŸ’αžŸαžΆαž–αŸαžαŸŒαž˜αžΆαž“αž’αŸ†αž–αžΈαžŸαž“αŸ’αž›αžΉαž€αž”αŸ’αžšαž—αž–αžŽαžΆαž˜αž½αž™ (αž“αž·αž„αž‡αžΆαž˜αž½αž™αžŸαžΌαž…αž“αžΆαž€αžšαž’αŸ’αžœαžΈαžαŸ’αž›αŸ‡) αžŠαŸ‚αž›αž”αžŽαŸ’αžαžΆαž›αž±αŸ’αž™αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž‰αŸ’αž…αžΌαž›αž€αŸ’αž“αž»αž„αž‚αŸ†αžšαžΌ - αž§αž‘αžΆαž αžšαžŽαŸ αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαžαžšαž”αžΆαž™αž€αžΆαžšαžŽαŸαžŸαž„αŸ’αžαŸαž” αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž”αŸ’αžšαž˜αžΌαž›αž•αŸ’αžαž»αŸ†αž‘αŸ…αž‡αžΆαžαŸ’αž“αžΆαŸ†αž„αŸ”

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
αž’αŸ’αžœαžΈβ€‹αžŠαŸ‚αž›β€‹αž”αž“αŸ’αž‘αžΆαž”αŸ‹β€‹αž˜αž€β€‹αž‚αž½αžšβ€‹αžαŸ‚β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž™αž€β€‹αž‘αŸ…β€‹αž‡αžΆβ€‹αž—αžŸαŸ’αžαž»αžαžΆαž„β€‹αž“αŸƒβ€‹αž‚αŸ†αž“αž·αžβ€‹αžαŸ‚β€‹αž˜αž½αž™β€‹αž‚αžαŸ‹ αž…αžΆαž”αŸ‹β€‹αžαžΆαŸ†αž„β€‹αž–αžΈβ€‹αžŸαŸ†αžŽαžΎβ€‹αž“αŸαŸ‡β€‹αž€αŸ’αž›αžΆαž™β€‹β€‹β€‹αž‘αŸ…β€‹αž‡αžΆβ€‹αž€αžΆαžšβ€‹αž›αŸ†αž”αžΆαž€β€‹αžαŸ’αž›αžΆαŸ†αž„β€‹αžŽαžΆαžŸαŸ‹β€‹αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž”αŸ’αžšαžŸαž·αž“αž”αžΎαžœαžΆαž‚αŸ’αžšαž”αžŠαžŽαŸ’αžαž”αŸ‹αž›αžΎαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€ αž’αŸ’αž“αž€αž‚αž½αžšαžαŸ‚αž‚αž·αžαž’αŸ†αž–αžΈαž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž”αž…αŸ’αž…αŸαž€αž‘αŸαžŸαžŸαŸ’αžšαžŠαŸ€αž„αž‚αŸ’αž“αžΆαŸ”

αž…αžΌαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‡αžΆαž˜αž½αž™αžŸαŸαž…αž€αŸ’αžαžΈαžαŸ’αž›αŸ‚αž„αž€αžΆαžšαžŽαŸαžŸαžΆαž˜αž‰αŸ’αž‰αž˜αž½αž™αž…αŸ†αž“αž½αž“αŸ–

  • αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžŠαžΌαž…αž‚αŸ’αž“αžΆαž–αžΈαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αžœαžΆαž‡αžΆαž€αžΆαžšαž›αŸ’αž’αž”αŸ†αž•αž»αžαž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αžΆαž“αžœαžΆαžαŸ‚αž˜αŸ’αžαž„.
  • αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž–αžΈαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αžœαžΆαž€αžΆαž“αŸ‹αžαŸ‚αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αžΆαž“αž‡αžΆαž”αžΆαž…αŸ‹αž‡αžΆαž„αž“αŸ…αž˜αŸ’αž“αžΆαž€αŸ‹αž―αž„αŸ”

αž₯αž‘αžΌαžœαž“αŸαŸ‡ αž…αžΌαžšαž™αžΎαž„αž–αŸ’αž™αžΆαž™αžΆαž˜αž”αž„αŸ’αž€αžΎαžαžŸαŸ†αžŽαžΎαžŠαŸ‚αž›αž™αžΎαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαŸ”

αž”αŸ„αŸ‡αž‡αŸ†αž αžΆαž“ 1

αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„ αž“αŸ…αž–αŸαž›αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž”αž„αŸ’αž€αžΎαžαž‘αžΎαž„αžœαž·αž‰ (αžαžΎαž™αžΎαž„αž“αžΉαž„αž“αŸ…αž―αžŽαžΆαžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αžœαžΆ!) αž™αžΎαž„αž“αžΉαž„αžαŸ’αžšαžΌαžœαžŠαž€αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž“αŸƒαžŸαŸ’αž›αžΉαž€αžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαžŸαŸ†αžŽαž»αŸ†αž“αŸƒαž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαžŠαŸ†αž”αžΌαž„αŸ–

WITH RECURSIVE tree AS (
  SELECT
    rec -- это Ρ†Π΅Π»ΡŒΠ½Π°Ρ запись Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹
  , id::text chld -- это "Π½Π°Π±ΠΎΡ€" ΠΏΡ€ΠΈΠ²Π΅Π΄ΡˆΠΈΡ… сюда исходных Π»ΠΈΡΡ‚ΡŒΠ΅Π²
  FROM
    hier rec
  WHERE
    id = ANY('{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192}'::integer[])
UNION ALL
  ...

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαžœαžΆαž αžΆαž€αŸ‹αžŠαžΌαž…αž‡αžΆαž…αž˜αŸ’αž›αŸ‚αž€αž…αŸ†αž–αŸ„αŸ‡αž“αžšαžŽαžΆαž˜αŸ’αž“αžΆαž€αŸ‹αžŠαŸ‚αž› "αžŸαŸ†αžŽαž»αŸ†" αžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž‡αžΆαžαŸ’αžŸαŸ‚αž’αž€αŸ’αžŸαžš αž αžΎαž™αž˜αž·αž“αž˜αŸ‚αž“αž‡αžΆαž’αžΆαžšαŸ αž“αŸ„αŸ‡αž˜αžΆαž“αž€αžΆαžšαž–αž“αŸ’αž™αž›αŸ‹αžŸαžΆαž˜αž‰αŸ’αž‰αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαžΏαž„αž“αŸαŸ‡αŸ” αž˜αžΆαž“αž˜αž»αžαž„αžΆαžš "αžŸαŸ’αž’αž·αžαž‡αžΆαž”αŸ‹" αžŠαŸ‚αž›αž—αŸ’αž‡αžΆαž”αŸ‹αž˜αž€αž‡αžΆαž˜αž½αž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ’αžŸαŸ‚ string_aggαž”αŸ‰αž»αž“αŸ’αžαŸ‚αž˜αž·αž“αž˜αŸ‚αž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžΆαžšαŸαž‘αŸαŸ” αž‘αŸ„αŸ‡αž”αžΈαž‡αžΆαž“αžΆαž„ αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž’αž“αž»αžœαžαŸ’αžαžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αŸ”.

αž”αŸ„αŸ‡αž‡αŸ†αž αžΆαž“ 2

αž₯αž‘αžΌαžœαž“αŸαŸ‡αž™αžΎαž„αž“αžΉαž„αž‘αž‘αž½αž›αž”αžΆαž“αžŸαŸ†αžŽαž»αŸ†αž“αŸƒαž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž•αŸ’αž“αŸ‚αž€αžŠαŸ‚αž›αž“αžΉαž„αžαŸ’αžšαžΌαžœαž’αžΆαž“αž”αž“αŸ’αžαŸ‚αž˜αŸ” αžŸαŸ’αž‘αžΎαžšαžαŸ‚αž‡αžΆαž“αž·αž…αŸ’αž…αž€αžΆαž› αž–αž½αž€αžœαžΆαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž˜αŸ’αž›αž„αž“αŸ…αž€αŸ’αž“αž»αž„αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž•αŸ’αžŸαŸαž„αŸ—αž‚αŸ’αž“αžΆαž“αŸƒαžŸαŸ†αžŽαž»αŸ†αžŠαžΎαž˜ - αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž™αžΎαž„αž“αžΉαž„ αž€αŸ’αžšαž»αž˜αž–αž½αž€αž‚αŸαŸ”αžαžŽαŸˆαž–αŸαž›αžŠαŸ‚αž›αžšαž€αŸ’αžŸαžΆαž–αŸαžαŸŒαž˜αžΆαž“αž’αŸ†αž–αžΈαžŸαŸ’αž›αžΉαž€αž”αŸ’αžšαž—αž–αŸ”

αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž“αŸ…αž‘αžΈαž“αŸαŸ‡αž”αž‰αŸ’αž αžΆαž”αžΈαž€αŸ†αž–αž»αž„αžšαž„αŸ‹αž…αžΆαŸ†αž™αžΎαž„:

  1. αž•αŸ’αž“αŸ‚αž€ "subrecursive" αž“αŸƒαžŸαŸ†αžŽαž½αžšαž˜αž·αž“αž’αžΆαž…αž˜αžΆαž“αž˜αž»αžαž„αžΆαžšαžŸαžšαž»αž”αž‡αžΆαž˜αž½αž™ GROUP BY.
  2. αžŸαŸαž…αž€αŸ’αžαžΈαž™αŸ„αž„αž‘αŸ… "αžαžΆαžšαžΆαž„" αžŠαŸ‚αž›αž’αžΆαž…αž”αŸ’αžšαžΎαž‘αžΎαž„αžœαž·αž‰αž”αžΆαž“ αž˜αž·αž“αž’αžΆαž…αžŸαŸ’αžαž·αžαž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ†αžŽαž½αžšαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž”αž“αŸ’αžŸαŸ†αž”αžΆαž“αž‘αŸαŸ”
  3. αžŸαŸ†αžŽαžΎαž“αŸ…αž€αŸ’αž“αž»αž„αž•αŸ’αž“αŸ‚αž€αžŠαŸ‚αž›αž”αŸ’αžšαžΎαž‘αžΎαž„αžœαž·αž‰αž˜αž·αž“αž’αžΆαž…αž˜αžΆαž“ CTE αž”αžΆαž“αž‘αŸαŸ”

αž‡αžΆαžŸαŸ†αžŽαžΆαž„αž›αŸ’αž’ αž”αž‰αŸ’αž αžΆαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡αž–αž·αžαž‡αžΆαž„αžΆαž™αžŸαŸ’αžšαž½αž›αž€αŸ’αž“αž»αž„αž€αžΆαžšαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αŸ” αž…αžΌαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž–αžΈαž‘αžΈαž”αž‰αŸ’αž…αž”αŸ‹αŸ”

CTE αž“αŸ…αž€αŸ’αž“αž»αž„αž•αŸ’αž“αŸ‚αž€ recursive

αž“αŸ…αž‘αžΈαž“αŸαŸ‡ αž˜αž·αž“αž˜αžΆαž“ αž’αŸ’αžœαžΎαž€αžΆαžšαŸ–

WITH RECURSIVE tree AS (
  ...
UNION ALL
  WITH T (...)
  SELECT ...
)

αž αžΎαž™αžŠαžΌαž…αŸ’αž“αŸαŸ‡αžœαžΆαžŠαŸ†αžŽαžΎαžšαž€αžΆαžš αžœαž„αŸ‹αž€αŸ’αžšαž…αž€αž’αŸ’αžœαžΎαž±αŸ’αž™αž˜αžΆαž“αž—αžΆαž–αžαž»αžŸαž‚αŸ’αž“αžΆ!

WITH RECURSIVE tree AS (
  ...
UNION ALL
  (
    WITH T (...)
    SELECT ...
  )
)

αžŸαŸ†αžŽαž½αžšβ€‹αžŠαŸ‚αž›β€‹αž”αžΆαž“β€‹αž—αŸ’αž‡αžΆαž”αŸ‹β€‹αž‡αžΆαž˜αž½αž™β€‹αž“αžΉαž„ "αžαžΆαžšαžΆαž„" αžŠαžŠαŸ‚αž›αŸ—

ហ៊ឺ... αž˜αž·αž“αž’αžΆαž…αž…αžΌαž›αž”αŸ’αžšαžΎ CTE αž‘αžΎαž„αžœαž·αž‰αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ†αžŽαž½αžšαžšαž„αž”αžΆαž“αž‘αŸαŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžœαžΆαž’αžΆαž…αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„ CTE! αž αžΎαž™β€‹αžŸαŸ†αžŽαžΎβ€‹αžŠαŸ‚αž›β€‹αž‡αžΆαž”αŸ‹β€‹αž‚αžΆαŸ†αž„β€‹αž’αžΆαž…β€‹αž…αžΌαž›β€‹αž”αŸ’αžšαžΎ CTE αž“αŸαŸ‡β€‹αž”αžΆαž“β€‹αž αžΎαž™!

GROUP BY αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αž€αžΆαžšαž αŸ…αž‘αžΎαž„αžœαž·αž‰

αžœαžΆβ€‹αž˜αž·αž“β€‹αžŸαž”αŸ’αž”αžΆαž™β€‹αž…αž·αžαŸ’αžβ€‹αž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚... αž™αžΎαž„β€‹αž˜αžΆαž“β€‹αžœαž·αž’αžΈβ€‹αžŸαžΆαž˜αž‰αŸ’αž‰β€‹αž˜αž½αž™β€‹αžŠαžΎαž˜αŸ’αž”αžΈβ€‹αžαŸ’αžšαžΆαž”αŸ‹αžαžΆαž˜β€‹αž€αŸ’αžšαž»αž˜β€‹αžŠαŸ„αž™β€‹αž€αžΆαžšβ€‹αž”αŸ’αžšαžΎ DISTINCT ON αž“αž·αž„αž˜αž»αžαž„αžΆαžšαž”αž„αŸ’αž’αž½αž…!

SELECT
  (rec).pid id
, string_agg(chld::text, ',') chld
FROM
  tree
WHERE
  (rec).pid IS NOT NULL
GROUP BY 1 -- Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚!

αž αžΎαž™αž“αŸαŸ‡αž‡αžΆαžšαž”αŸ€αž”αžŠαŸ‚αž›αžœαžΆαžŠαŸ†αžŽαžΎαžšαž€αžΆαžš!

SELECT DISTINCT ON((rec).pid)
  (rec).pid id
, string_agg(chld::text, ',') OVER(PARTITION BY (rec).pid) chld
FROM
  tree
WHERE
  (rec).pid IS NOT NULL

αž₯αž‘αžΌαžœαž“αŸαŸ‡ αž™αžΎαž„αžƒαžΎαž‰αž˜αžΌαž›αž αŸαžαž»αžŠαŸ‚αž›αž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž›αŸαžαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™αž‘αŸ…αž‡αžΆαž’αžαŸ’αžαž”αž‘ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž–αž½αž€αž‚αŸαž’αžΆαž…αž—αŸ’αž‡αžΆαž”αŸ‹αž‡αžΆαž˜αž½αž™αž‚αŸ’αž“αžΆαžŠαŸ„αž™αž”αŸ†αž”αŸ‚αž€αžŠαŸ„αž™αž€αŸ’αž”αŸ€αžŸ!

αž”αŸ„αŸ‡αž‡αŸ†αž αžΆαž“ 3

αžŸαž˜αŸ’αžšαžΆαž”αŸ‹β€‹αžœαž‚αŸ’αž‚β€‹αž•αŸ’αžŠαžΆαž…αŸ‹αž–αŸ’αžšαŸαžαŸ’αžš αž™αžΎαž„β€‹αž‚αŸ’αž˜αžΆαž“β€‹αžŸαž›αŸ‹β€‹αž’αŸ’αžœαžΈβ€‹αž‘αžΎαž™αŸ–

  • αž™αžΎαž„αž’αžΆαž“αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆ "αž•αŸ’αž“αŸ‚αž€" αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαžŸαŸ†αžŽαž»αŸ†αž“αŸƒαž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž€αŸ’αžšαž»αž˜
  • αž™αžΎαž„αž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž•αŸ’αž“αŸ‚αž€αžŠαž€αž‡αžΆαž˜αž½αž™ "αžŸαŸ†αžŽαž»αŸ†" αž“αŸƒαžŸαž“αŸ’αž›αžΉαž€αžŠαžΎαž˜
  • "αž–αž„αŸ’αžšαžΈαž€" αžαŸ’αžŸαŸ‚αž’αž€αŸ’αžŸαžšαžŠαŸ‚αž›αž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžŠαŸ„αž™αž”αŸ’αžšαžΎ unnest(string_to_array(chld, ',')::integer[])

WITH RECURSIVE tree AS (
  SELECT
    rec
  , id::text chld
  FROM
    hier rec
  WHERE
    id = ANY('{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192}'::integer[])
UNION ALL
  (
    WITH prnt AS (
      SELECT DISTINCT ON((rec).pid)
        (rec).pid id
      , string_agg(chld::text, ',') OVER(PARTITION BY (rec).pid) chld
      FROM
        tree
      WHERE
        (rec).pid IS NOT NULL
    )
    , nodes AS (
      SELECT
        rec
      FROM
        hier rec
      WHERE
        id = ANY(ARRAY(
          SELECT
            id
          FROM
            prnt
        ))
    )
    SELECT
      nodes.rec
    , prnt.chld
    FROM
      prnt
    JOIN
      nodes
        ON (nodes.rec).id = prnt.id
  )
)
SELECT
  unnest(string_to_array(chld, ',')::integer[]) leaf
, (rec).*
FROM
  tree;

PostgreSQL AntipatternsαŸ– αžαžΎαž”αŸ’αžšαž αŸ„αž„αž‘αž“αŸ’αžŸαžΆαž™αž˜αžΆαž“αž‡αž˜αŸ’αžšαŸ…αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“? αž…αžΌαžšαž™αžΎαž„αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‹αžΆαž“αžΆαž“αž»αž€αŸ’αžšαž˜
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹