SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"

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

เบ•เบปเบงเบขเปˆเบฒเบ‡ "เบŠเบตเบงเบดเบ”เบˆเบดเบ‡" เบ—เบตเปˆเบชเบธเบ”เปเบกเปˆเบ™เบเบฒเบ™เบชเบฐเปเบ”เบ‡ 20 เบšเบฑเบ™เบซเบฒเป€เบเบปเปˆเบฒเปเบเปˆเบ—เบตเปˆเบชเบธเบ”, เบฅเบฒเบเบŠเบทเปˆ เปƒเบ™โ€‹เบšเบฑเบ™โ€‹เบŠเบตโ€‹เบฅเบฒเบโ€‹เบŠเบทเปˆโ€‹เบ‚เบญเบ‡โ€‹เบžเบฐโ€‹เบ™เบฑเบโ€‹เบ‡เบฒเบ™โ€‹ (เบ•เบปเบงเบขเปˆเบฒเบ‡, เบžเบฒเบเปƒเบ™เบซเบ™เบถเปˆเบ‡เบžเบฐเปเบ™เบ). เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ„เบธเป‰เบกเบ„เบญเบ‡เบ•เปˆเบฒเบ‡เป† "dashboards" เบ—เบตเปˆเบกเบตเบšเบปเบ”เบชเบฐเบซเบผเบธเบšเบชเบฑเป‰เบ™เป†เบ‚เบญเบ‡เบžเบทเป‰เบ™เบ—เบตเปˆเป€เบฎเบฑเบ”เบงเบฝเบ, เบซเบปเบงเบ‚เปเป‰เบ—เบตเปˆเบ„เป‰เบฒเบเบ„เบทเบเบฑเบ™เปเบกเปˆเบ™เบ•เป‰เบญเบ‡เบเบฒเบ™เป€เบฅเบทเป‰เบญเบเป†.

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"

เปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบกเบ™เบตเป‰เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเป€เบšเบดเปˆเบ‡เบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ”เปƒเบ™ PostgreSQL เบ‚เบญเบ‡เบเบฒเบ™เปเบเป‰เป„เบ‚ "naive" เบชเปเบฒเบฅเบฑเบšเบšเบฑเบ™เบซเบฒเบ”เบฑเปˆเบ‡เบเปˆเบฒเบง, เป€เบ›เบฑเบ™ "smarter" เปเบฅเบฐ algorithm เบชเบฐเบฅเบฑเบšเบชเบฑเบšเบŠเป‰เบญเบ™เบซเบผเบฒเบ. "loop" เปƒเบ™ SQL เบ—เบตเปˆเบกเบตเป€เบ‡เบทเปˆเบญเบ™เป„เบ‚เบญเบญเบเบˆเบฒเบเบ‚เปเป‰เบกเบนเบ™เบ—เบตเปˆเบžเบปเบšเป€เบซเบฑเบ™, เบŠเบถเปˆเบ‡เบชเบฒเบกเบฒเบ”เป€เบ›เบฑเบ™เบ›เบฐเป‚เบซเบเบ”เบ—เบฑเบ‡เบเบฒเบ™เบžเบฑเบ”เบ—เบฐเบ™เบฒเบ—เบปเปˆเบงเป„เบ›เปเบฅเบฐเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰เปƒเบ™เบเปเบฅเบฐเบ™เบตเบ—เบตเปˆเบ„เป‰เบฒเบเบ„เบทเบเบฑเบ™เบญเบทเปˆเบ™เป†.

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

CREATE INDEX ON task(owner_id, task_date, id);
-- ะฐ ัั‚ะฐั€ั‹ะน - ัƒะดะฐะปะธะผ
DROP INDEX task_owner_id_task_date_idx;

เบ•เบฒเบกโ€‹เบ—เบตเปˆโ€‹เป„เบ”เป‰โ€‹เบเบดเบ™, เบ”เบฑเปˆเบ‡โ€‹เบ™เบฑเป‰เบ™โ€‹เบˆเบถเปˆเบ‡โ€‹เบ‚เบฝเบ™

เบ—เปเบฒเบญเบดเบ”, เปƒเบซเป‰เป€เบฎเบปเบฒเปเบ•เป‰เบกเบชเบฐเบšเบฑเบšเบ—เบตเปˆเบ‡เปˆเบฒเบเบ”เบฒเบเบ—เบตเปˆเบชเบธเบ”เบ‚เบญเบ‡เบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เป, เบœเปˆเบฒเบ™ IDs เบ‚เบญเบ‡เบ™เบฑเบเบชเบฐเปเบ”เบ‡ array เป€เบ›เบฑเบ™เบžเบฒเบฅเบฒเบกเบดเป€เบ•เบตเบเบฒเบ™เบ›เป‰เบญเบ™เบ‚เปเป‰เบกเบนเบ™:

SELECT
  *
FROM
  task
WHERE
  owner_id = ANY('{1,2,4,8,16,32,64,128,256,512}'::integer[])
ORDER BY
  task_date, id
LIMIT 20;

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ„เบงเบฒเบกเป‚เบชเบเป€เบชเบปเป‰เบฒเป€เบฅเบฑเบเบ™เป‰เบญเบ - เบžเบงเบเป€เบฎเบปเบฒเบชเบฑเปˆเบ‡เบžเบฝเบ‡เปเบ•เปˆ 20 เบšเบฑเบ™เบ—เบถเบ, เปเบ•เปˆ Index Scan เบชเบปเปˆเบ‡เบ„เบทเบ™เบกเบฑเบ™เปƒเบซเป‰เบžเบงเบเป€เบฎเบปเบฒ 960 เป€เบชเบฑเป‰เบ™, เป€เบŠเบดเปˆเบ‡เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบเปเปˆเบ•เป‰เบญเบ‡เป„เบ”เป‰เบˆเบฑเบ”เบฎเบฝเบ‡ ... เปƒเบซเป‰เบžเบฐเบเบฒเบเบฒเบกเบญเปˆเบฒเบ™เบซเบ™เป‰เบญเบเบฅเบปเบ‡.

unnest + ARRAY

เบเบฒเบ™เบžเบดเบˆเบฒเบฅเบฐเบ™เบฒเบ—เปเบฒเบญเบดเบ”เบ—เบตเปˆเบˆเบฐเบŠเปˆเบงเบเปƒเบซเป‰เบžเบงเบเป€เบฎเบปเบฒเปเบกเปˆเบ™เบ–เป‰เบฒเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™ เบžเบฝเบ‡เปเบ•เปˆ 20 เบ„เบฑเบ” เบšเบฑเบ™เบ—เบถเบ, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบžเบฝเบ‡เปเบ•เปˆเบญเปˆเบฒเบ™ เบšเปเปˆเป€เบเบตเบ™ 20 เบˆเบฑเบ”เบฎเบฝเบ‡เบ•เบฒเบกเบฅเบณเบ”เบฑเบšเบ”เบฝเบงเบเบฑเบ™เบชเบณเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเบญเบฑเบ™ เบเบฐเปเบˆ. เบ”เบต, เบ”เบฑเบ”โ€‹เบŠเบฐโ€‹เบ™เบตโ€‹เบ—เบตเปˆโ€‹เป€เบซเบกเบฒเบฐโ€‹เบชเบปเบกโ€‹ (owner_id, task_date, id) เบžเบงเบเป€เบฎเบปเบฒเบกเบต.

เปƒเบซเป‰เปƒเบŠเป‰เบเบปเบ™เป„เบเบ”เบฝเบงเบเบฑเบ™เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบชเบฐเบเบฑเบ”เปเบฅเบฐ "เปเบœเปˆเป€เบ‚เบปเป‰เบฒเป„เบ›เปƒเบ™เบ–เบฑเบ™" เบšเบฑเบ™เบ—เบถเบเบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบ›เบฐเบชเบปเบกเบ›เบฐเบชเบฒเบ™, เปƒเบ™โ€‹เบ–เบฒโ€‹เบ™เบฐโ€‹เป€เบ›เบฑเบ™โ€‹ เบšเบปเบ”เบ„เบงเบฒเบกเบชเบธเบ”เบ—เป‰เบฒเบ. เบžเบงเบเป€เบฎเบปเบฒเบเบฑเบ‡เบชเบฒเบกเบฒเบ”เปƒเบŠเป‰ folding เป€เบ‚เบปเป‰เบฒเป„เบ›เปƒเบ™ array เป‚เบ”เบเปƒเบŠเป‰เบŸเบฑเบ‡เบŠเบฑเบ™ ARRAY():

WITH T AS (
  SELECT
    unnest(ARRAY(
      SELECT
        t
      FROM
        task t
      WHERE
        owner_id = unnest
      ORDER BY
        task_date, id
      LIMIT 20 -- ะพะณั€ะฐะฝะธั‡ะธะฒะฐะตะผ ั‚ัƒั‚...
    )) r
  FROM
    unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
)
SELECT
  (r).*
FROM
  T
ORDER BY
  (r).task_date, (r).id
LIMIT 20; -- ... ะธ ั‚ัƒั‚ - ั‚ะพะถะต

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เป‚เบญเป‰, เบ”เบตเบเบงเปˆเบฒเปเบฅเป‰เบง! เป„เบงเบเบงเปˆเบฒ 40% เปเบฅเบฐเบ‚เปเป‰เบกเบนเบ™เปœเป‰เบญเบเบเบงเปˆเบฒ 4.5 เป€เบ—เบปเปˆเบฒ เบ‚เป‰เบญเบเบ•เป‰เบญเบ‡เบญเปˆเบฒเบ™เบกเบฑเบ™.

เบงเบฑเบ”เบชเบฐเบ”เบธเบ‚เบญเบ‡เบšเบฑเบ™เบ—เบถเบเบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบœเปˆเบฒเบ™ CTEเปƒเบซเป‰เบ‚เป‰เบญเบเบ”เบถเบ‡เบ”เบนเบ”เบ„เบงเบฒเบกเบชเบปเบ™เปƒเบˆเบ‚เบญเบ‡เป€เบˆเบปเป‰เบฒเบเบฑเบšเบ„เบงเบฒเบกเบˆเบดเบ‡เบ—เบตเปˆเบงเปˆเบฒ เปƒเบ™โ€‹เบšเบฒเบ‡โ€‹เบเปโ€‹เบฅเบฐโ€‹เบ™เบต เบ„เบงเบฒเบกเบžเบฐเบเบฒเบเบฒเบกเบ—เบตเปˆเบˆเบฐเป€เบฎเบฑเบ”เบงเบฝเบเบ—เบฑเบ™เบ—เบตเบ—เบฑเบ™เปƒเบ”เบเบฑเบšเบžเบฒเบเบชเบฐเบซเบ™เบฒเบกเบ‚เบญเบ‡เบšเบฑเบ™เบ—เบถเบเบซเบผเบฑเบ‡เบˆเบฒเบเบเบฒเบ™เบŠเบญเบเบซเบฒเบกเบฑเบ™เบขเบนเปˆเปƒเบ™ subquery, เป‚เบ”เบเบšเปเปˆเบกเบตเบเบฒเบ™ "เบซเปเปˆ" เบกเบฑเบ™เบขเบนเปˆเปƒเบ™ CTE, เบชเบฒเบกเบฒเบ”เบ™เปเบฒเป„เบ›เบชเบนเปˆเบเบฒเบ™. "เบ„เบนเบ™" InitPlan เบญเบฑเบ”เบ•เบฒเบชเปˆเบงเบ™เบเบฑเบšเบˆเปเบฒเบ™เบงเบ™เบŠเปˆเบญเบ‡เบ‚เปเป‰เบกเบนเบ™เบ”เบฝเบงเบเบฑเบ™เป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰:

SELECT
  ((
    SELECT
      t
    FROM
      task t
    WHERE
      owner_id = 1
    ORDER BY
      task_date, id
    LIMIT 1
  ).*);

Result  (cost=4.77..4.78 rows=1 width=16) (actual time=0.063..0.063 rows=1 loops=1)
  Buffers: shared hit=16
  InitPlan 1 (returns $0)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.031..0.032 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t  (cost=0.42..387.57 rows=500 width=48) (actual time=0.030..0.030 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4
  InitPlan 2 (returns $1)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.009 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_1  (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4
  InitPlan 3 (returns $2)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.008..0.008 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_2  (cost=0.42..387.57 rows=500 width=48) (actual time=0.008..0.008 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4"
  InitPlan 4 (returns $3)
    ->  Limit  (cost=0.42..1.19 rows=1 width=48) (actual time=0.009..0.009 rows=1 loops=1)
          Buffers: shared hit=4
          ->  Index Scan using task_owner_id_task_date_id_idx on task t_3  (cost=0.42..387.57 rows=500 width=48) (actual time=0.009..0.009 rows=1 loops=1)
                Index Cond: (owner_id = 1)
                Buffers: shared hit=4

เบšเบฑเบ™เบ—เบถเบเบ”เบฝเบงเบเบฑเบ™เป„เบ”เป‰เบ–เบทเบ "เป€เบšเบดเปˆเบ‡" 4 เป€เบ—เบทเปˆเบญ ... เบˆเบปเบ™เบเปˆเบงเบฒ PostgreSQL 11, เบžเบถเบ”เบ•เบดเบเปเบฒเบ™เบตเป‰เป€เบเบตเบ”เบ‚เบถเป‰เบ™เป€เบ›เบฑเบ™เบ›เบปเบเบเบฐเบ•เบด, เปเบฅเบฐเบเบฒเบ™เปเบเป‰เป„เบ‚เปเบกเปˆเบ™เป€เบžเบทเปˆเบญ "เบซเปเปˆ" เบกเบฑเบ™เบขเบนเปˆเปƒเบ™ CTE, เป€เบŠเบดเปˆเบ‡เป€เบ›เบฑเบ™เบ‚เบญเบšเป€เบ‚เบ”เบˆเปเบฒเบเบฑเบ”เบขเปˆเบฒเบ‡เปเบ—เป‰เบˆเบดเบ‡เบชเปเบฒเบฅเบฑเบš optimizer เปƒเบ™เบชเบฐเบšเบฑเบšเป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰.

เบ„เบฑเบ‡เบชเบฐเบชเบปเบก Recursive

เปƒเบ™เบชเบฐเบšเบฑเบšเบ—เบตเปˆเบœเปˆเบฒเบ™เบกเบฒ, เบžเบงเบเป€เบฎเบปเบฒเบญเปˆเบฒเบ™เบ—เบฑเบ‡เบซเบกเบปเบ” 200 เป€เบชเบฑเป‰เบ™ เบชเปเบฒเบฅเบฑเบš sake เบ‚เบญเบ‡เบ„เบงเบฒเบกเบ•เป‰เบญเบ‡เบเบฒเบ™ 20. เบšเปเปˆเปเบกเปˆเบ™ 960, เปเบ•เปˆเป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเบซเบ™เป‰เบญเบ - เบกเบฑเบ™เป€เบ›เบฑเบ™เป„เบ›เป„เบ”เป‰เบšเป?

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

เบ‚เบฑเป‰เบ™เบ•เบญเบ™เบ—เบต 1: เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบฅเบฒเบเบเบฒเบ™

เปเบ™เปˆเบ™เบญเบ™, เบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆ "เป€เบ›เบปเป‰เบฒเบซเบกเบฒเบ" เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเบ‚เบญเบ‡ 20 เบšเบฑเบ™เบ—เบถเบเบ„เบงเบ™เป€เบฅเบตเปˆเบกเบ•เบปเป‰เบ™เบ”เป‰เบงเบเบšเบฑเบ™เบ—เบถเบ "เบ—เปเบฒเบญเบดเบ”" เบชเปเบฒเบฅเบฑเบšเบซเบ™เบถเปˆเบ‡เปƒเบ™เบฅเบฐเบซเบฑเบ” owner_id เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ. เป€เบžเบฒเบฐเบชเบฐเบ™เบฑเป‰เบ™, เบ—เปเบฒเบญเบดเบ”เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบŠเบญเบเบซเบฒเบชเบดเปˆเบ‡เบ”เบฑเปˆเบ‡เบเปˆเบฒเบง "เบ—เปเบฒเบญเบดเบ”" เบชเปเบฒเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเบเบฐเปเบˆ เปเบฅเบฐเป€เบžเบตเปˆเบกเบกเบฑเบ™เป€เบ‚เบปเป‰เบฒเปƒเบ™เบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆ, เบˆเบฑเบ”เบฎเบฝเบ‡เบ•เบฒเบกเบฅเปเบฒเบ”เบฑเบšเบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™ - (task_date, id).

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"

เบ‚เบฑเป‰เบ™เบ•เบญเบ™เบ—เบต 2: เบŠเบญเบเบซเบฒเบฅเบฒเบเบเบฒเบ™ "เบ•เปเปˆเป„เบ›".

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

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

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"

เบ™เบฑเป‰เบ™เปเบกเปˆเบ™, เบžเบงเบเป€เบฎเบปเบฒเบชเบฐเป€เบซเบกเบตเป„เบ”เป‰เบฎเบฑเบšเบงเปˆเบฒเบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆเบšเปเปˆเบกเบตเบซเบผเบฒเบเบเปˆเบงเบฒเบซเบ™เบถเปˆเบ‡เบฅเบฒเบเบเบฒเบ™เบชเปเบฒเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเบเบฐเปเบˆ (เบ–เป‰เบฒเบฅเบฒเบเบเบฒเบ™เบซเบกเบปเบ”เป„เบ›เปเบฅเบฐเบžเบงเบเป€เบฎเบปเบฒเบšเปเปˆ "เบ‚เป‰เบฒเบก", เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบฅเบฒเบเบเบฒเบ™เบ—เปเบฒเบญเบดเบ”เบˆเบฒเบเบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆเบˆเบฐเบซเบฒเบเป„เบ›เปเบฅเบฐเบšเปเปˆเบกเบตเบซเบเบฑเบ‡เบˆเบฐเป€เบžเบตเปˆเบก. ), เปเบฅเบฐเบžเบงเบเป€เบ‚เบปเบฒ เบˆเบฑเบ”เบฎเบฝเบ‡เบชเบฐ เป€เปเบต เปƒเบ™เบฅเปเบฒเบ”เบฑเบšเบ•เบฑเป‰เบ‡เบŠเบฑเบ™เบ‚เบถเป‰เบ™เบ‚เบญเบ‡เบฅเบฐเบซเบฑเบ”เบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบ (task_date, id).

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"

เบ‚เบฑเป‰เบ™เบ•เบญเบ™เบ—เบต 3: เบเบฒเบ™เบเบฑเปˆเบ™เบ•เบญเบ‡เปเบฅเบฐ "เบ‚เบฐเบซเบเบฒเบ" เบšเบฑเบ™เบ—เบถเบ

เปƒเบ™เบšเบฒเบ‡เปเบ–เบงเบ‚เบญเบ‡เบเบฒเบ™เบ„เบฑเบ”เป€เบฅเบทเบญเบ recursive เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ, เบšเบฒเบ‡เบšเบฑเบ™เบ—เบถเบ rv เบ–เบทเบเบŠเป‰เปเบฒเบเบฑเบ™ - เบ—เปเบฒเบญเบดเบ”เบžเบงเบเป€เบฎเบปเบฒเบŠเบญเบเบซเบฒเป€เบŠเบฑเปˆเบ™ "เบ‚เป‰เบฒเบกเบŠเบฒเบเปเบ”เบ™เบ‚เบญเบ‡เบฅเบฒเบเบเบฒเบ™เบ—เบต 2 เบ‚เบญเบ‡เบฅเบฒเบเบเบฒเบ™", เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบ—เบปเบ”เปเบ—เบ™เบกเบฑเบ™เป€เบ›เบฑเบ™เบญเบฑเบ™เบ”เบฑเบšเบ—เบต 1 เบˆเบฒเบเบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆ. เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™เบเบฒเบ™เบ›เบฐเบเบปเบ”เบ•เบปเบงเบ„เบฑเป‰เบ‡เบ—เปเบฒเบญเบดเบ”เบ•เป‰เบญเบ‡เป„เบ”เป‰เบฎเบฑเบšเบเบฒเบ™เบเบฑเปˆเบ™เบ•เบญเบ‡.

เบเบฒเบ™เบชเบญเบšเบ–เบฒเบกเบชเบธเบ”เบ—เป‰เบฒเบเบ—เบตเปˆเบซเบ™เป‰เบฒเบขเป‰เบฒเบ™

WITH RECURSIVE T AS (
  -- #1 : ะทะฐะฝะพัะธะผ ะฒ ัะฟะธัะพะบ "ะฟะตั€ะฒั‹ะต" ะทะฐะฟะธัะธ ะฟะพ ะบะฐะถะดะพะผัƒ ะธะท ะบะปัŽั‡ะตะน ะฝะฐะฑะพั€ะฐ
  WITH wrap AS ( -- "ะผะฐั‚ะตั€ะธะฐะปะธะทัƒะตะผ" record'ั‹, ั‡ั‚ะพะฑั‹ ะพะฑั€ะฐั‰ะตะฝะธะต ะบ ะฟะพะปัะผ ะฝะต ะฒั‹ะทั‹ะฒะฐะปะพ ัƒะผะฝะพะถะตะฝะธั InitPlan/SubPlan
    WITH T AS (
      SELECT
        (
          SELECT
            r
          FROM
            task r
          WHERE
            owner_id = unnest
          ORDER BY
            task_date, id
          LIMIT 1
        ) r
      FROM
        unnest('{1,2,4,8,16,32,64,128,256,512}'::integer[])
    )
    SELECT
      array_agg(r ORDER BY (r).task_date, (r).id) list -- ัะพั€ั‚ะธั€ัƒะตะผ ัะฟะธัะพะบ ะฒ ะฝัƒะถะฝะพะผ ะฟะพั€ัะดะบะต
    FROM
      T
  )
  SELECT
    list
  , list[1] rv
  , FALSE not_cross
  , 0 size
  FROM
    wrap
UNION ALL
  -- #2 : ะฒั‹ั‡ะธั‚ั‹ะฒะฐะตะผ ะทะฐะฟะธัะธ 1-ะณะพ ะฟะพ ะฟะพั€ัะดะบัƒ ะบะปัŽั‡ะฐ, ะฟะพะบะฐ ะฝะต ะฟะตั€ะตัˆะฐะณะฝะตะผ ั‡ะตั€ะตะท ะทะฐะฟะธััŒ 2-ะณะพ
  SELECT
    CASE
      -- ะตัะปะธ ะฝะธั‡ะตะณะพ ะฝะต ะฝะฐะนะดะตะฝะพ ะดะปั ะบะปัŽั‡ะฐ 1-ะน ะทะฐะฟะธัะธ
      WHEN X._r IS NOT DISTINCT FROM NULL THEN
        T.list[2:] -- ัƒะฑะธั€ะฐะตะผ ะตะต ะธะท ัะฟะธัะบะฐ
      -- ะตัะปะธ ะผั‹ ะะ• ะฟะตั€ะตัะตะบะปะธ ะฟั€ะธะบะปะฐะดะฝะพะน ะบะปัŽั‡ 2-ะน ะทะฐะฟะธัะธ
      WHEN X.not_cross THEN
        T.list -- ะฟั€ะพัั‚ะพ ะฟั€ะพั‚ัะณะธะฒะฐะตะผ ั‚ะพั‚ ะถะต ัะฟะธัะพะบ ะฑะตะท ะผะพะดะธั„ะธะบะฐั†ะธะน
      -- ะตัะปะธ ะฒ ัะฟะธัะบะต ัƒะถะต ะฝะตั‚ 2-ะน ะทะฐะฟะธัะธ
      WHEN T.list[2] IS NULL THEN
        -- ะฟั€ะพัั‚ะพ ะฒะพะทะฒั€ะฐั‰ะฐะตะผ ะฟัƒัั‚ะพะน ัะฟะธัะพะบ
        '{}'
      -- ะฟะตั€ะตัะพั€ั‚ะธั€ะพะฒั‹ะฒะฐะตะผ ัะปะพะฒะฐั€ัŒ, ัƒะฑะธั€ะฐั 1-ัŽ ะทะฐะฟะธััŒ ะธ ะดะพะฑะฐะฒะปัั ะฟะพัะปะตะดะฝัŽัŽ ะธะท ะฝะฐะนะดะตะฝะฝั‹ั…
      ELSE (
        SELECT
          coalesce(T.list[2] || array_agg(r ORDER BY (r).task_date, (r).id), '{}')
        FROM
          unnest(T.list[3:] || X._r) r
      )
    END
  , X._r
  , X.not_cross
  , T.size + X.not_cross::integer
  FROM
    T
  , LATERAL(
      WITH wrap AS ( -- "ะผะฐั‚ะตั€ะธะฐะปะธะทัƒะตะผ" record
        SELECT
          CASE
            -- ะตัะปะธ ะฒัะต-ั‚ะฐะบะธ "ะฟะตั€ะตัˆะฐะณะฝัƒะปะธ" ั‡ะตั€ะตะท 2-ัŽ ะทะฐะฟะธััŒ
            WHEN NOT T.not_cross
              -- ั‚ะพ ะฝัƒะถะฝะฐั ะทะฐะฟะธััŒ - ะฟะตั€ะฒะฐั ะธะท ัะฟะฟะธัะบะฐ
              THEN T.list[1]
            ELSE ( -- ะตัะปะธ ะฝะต ะฟะตั€ะตัะตะบะปะธ, ั‚ะพ ะบะปัŽั‡ ะพัั‚ะฐะปัั ะบะฐะบ ะฒ ะฟั€ะตะดั‹ะดัƒั‰ะตะน ะทะฐะฟะธัะธ - ะพั‚ั‚ะฐะปะบะธะฒะฐะตะผัั ะพั‚ ะฝะตะต
              SELECT
                _r
              FROM
                task _r
              WHERE
                owner_id = (rv).owner_id AND
                (task_date, id) > ((rv).task_date, (rv).id)
              ORDER BY
                task_date, id
              LIMIT 1
            )
          END _r
      )
      SELECT
        _r
      , CASE
          -- ะตัะปะธ 2-ะน ะทะฐะฟะธัะธ ัƒะถะต ะฝะตั‚ ะฒ ัะฟะธัะบะต, ะฝะพ ะผั‹ ั…ะพั‚ัŒ ั‡ั‚ะพ-ั‚ะพ ะฝะฐัˆะปะธ
          WHEN list[2] IS NULL AND _r IS DISTINCT FROM NULL THEN
            TRUE
          ELSE -- ะฝะธั‡ะตะณะพ ะฝะต ะฝะฐัˆะปะธ ะธะปะธ "ะฟะตั€ะตัˆะฐะณะฝัƒะปะธ"
            coalesce(((_r).task_date, (_r).id) < ((list[2]).task_date, (list[2]).id), FALSE)
        END not_cross
      FROM
        wrap
    ) X
  WHERE
    T.size < 20 AND -- ะพะณั€ะฐะฝะธั‡ะธะฒะฐะตะผ ั‚ัƒั‚ ะบะพะปะธั‡ะตัั‚ะฒะพ
    T.list IS DISTINCT FROM '{}' -- ะธะปะธ ะฟะพะบะฐ ัะฟะธัะพะบ ะฝะต ะบะพะฝั‡ะธะปัั
)
-- #3 : "ั€ะฐะทะฒะพั€ะฐั‡ะธะฒะฐะตะผ" ะทะฐะฟะธัะธ - ะฟะพั€ัะดะพะบ ะณะฐั€ะฐะฝั‚ะธั€ะพะฒะฐะฝ ะฟะพ ะฟะพัั‚ั€ะพะตะฝะธัŽ
SELECT
  (rv).*
FROM
  T
WHERE
  not_cross; -- ะฑะตั€ะตะผ ั‚ะพะปัŒะบะพ "ะฝะตะฟะตั€ะตัะตะบะฐัŽั‰ะธะต" ะทะฐะฟะธัะธ

SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡"
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™, เบžเบงเบเป€เบฎเบปเบฒ เบŠเบทเป‰เบ‚เบฒเบ 50% เบ‚เบญเบ‡เบ‚เปเป‰เบกเบนเบ™เบญเปˆเบฒเบ™เบชเปเบฒเบฅเบฑเบš 20% เบ‚เบญเบ‡เป€เบงเบฅเบฒเบ›เบฐเบ•เบดเบšเบฑเบ”. เบ™เบฑเป‰เบ™เปเบกเปˆเบ™, เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบกเบตเป€เบซเบ”เบœเบปเบ™เบ—เบตเปˆเบˆเบฐเป€เบŠเบทเปˆเบญเบงเปˆเบฒเบเบฒเบ™เบญเปˆเบฒเบ™เบญเบฒเบ”เบˆเบฐเปƒเบŠเป‰เป€เบงเบฅเบฒเบ”เบปเบ™ (เบ•เบปเบงเบขเปˆเบฒเบ‡, เบ‚เปเป‰เบกเบนเบ™เบกเบฑเบเบˆเบฐเบšเปเปˆเบขเบนเปˆเปƒเบ™เปเบ„เบ”, เปเบฅเบฐเบ—เปˆเบฒเบ™เบ•เป‰เบญเบ‡เป„เบ›เบซเบฒเปเบœเปˆเบ™เบชเปเบฒเบฅเบฑเบšเบกเบฑเบ™), เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบ”เป‰เบงเบเบงเบดเบ—เบตเบ™เบตเป‰, เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ‚เบถเป‰เบ™เบเบฑเบšเบเบฒเบ™เบญเปˆเบฒเบ™เบซเบ™เป‰เบญเบเบฅเบปเบ‡. .

เปƒเบ™เบเปเบฅเบฐเบ™เบตเปƒเบ”เบเปเปˆเบ•เบฒเบก, เป€เบงเบฅเบฒเบ›เบฐเบ•เบดเบšเบฑเบ”เป„เบ”เป‰เบ”เบตเบเบงเปˆเบฒเปƒเบ™เบ—เบฒเบ‡เป€เบฅเบทเบญเบเบ—เปเบฒเบญเบดเบ” "เป‚เบ‡เปˆ". เปเบ•เปˆเบงเปˆเบฒเปƒเบ™ 3 เบ—เบฒเบ‡เป€เบฅเบทเบญเบเบ™เบตเป‰เบˆเบฐเปƒเบŠเป‰เบญเบฑเบ™เปƒเบ”เปเบกเปˆเบ™เบ‚เบถเป‰เบ™เบเบฑเบšเบ—เปˆเบฒเบ™.

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

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