SQL HowTo: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹

เชธเชฎเชฏเชพเช‚เชคเชฐเซ‡, เช•เซ€เชจเชพ เชธเชฎเซ‚เชนเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชธเช‚เชฌเช‚เชงเชฟเชค เชกเซ‡เชŸเชพ เชถเซ‹เชงเชตเชพเชจเซเช‚ เช•เชพเชฐเซเชฏ เช‰เชฆเซเชญเชตเซ‡ เช›เซ‡. เชœเซเชฏเชพเช‚ เชธเซเชงเซ€ เช…เชฎเชจเซ‡ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเซ€ เช†เชตเชถเซเชฏเช• เช•เซเชฒ เชธเช‚เช–เซเชฏเชพ เชจ เชฎเชณเซ‡.

เชธเซŒเชฅเซ€ "เชตเชพเชธเซเชคเชตเชฟเช• เชœเซ€เชตเชจ" เช‰เชฆเชพเชนเชฐเชฃ เชฆเชฐเซเชถเชพเชตเชตเชพเชจเซเช‚ เช›เซ‡ 20 เชธเซŒเชฅเซ€ เชœเซ‚เชจเซ€ เชธเชฎเชธเซเชฏเชพเช“, เชธเซ‚เชšเชฟเชฌเชฆเซเชง เช•เชฐเซเชฎเชšเชพเชฐเซ€เช“เชจเซ€ เชฏเชพเชฆเซ€เชฎเชพเช‚ (เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชเช• เชตเชฟเชญเชพเช—เชจเซ€ เช…เช‚เชฆเชฐ). เช•เชพเชฐเซเชฏเช•เซเชทเซ‡เชคเซเชฐเซ‹เชจเชพ เชธเช‚เช•เซเชทเชฟเชชเซเชค เชธเชพเชฐเชพเช‚เชถ เชธเชพเชฅเซ‡ เชตเชฟเชตเชฟเชง เชฎเซ‡เชจเซ‡เชœเชฎเซ‡เชจเซเชŸ "เชกเซ…เชถเชฌเซ‹เชฐเซเชกเซเชธ" เชฎเชพเชŸเซ‡, เชธเชฎเชพเชจ เชตเชฟเชทเชฏเชจเซ€ เช˜เชฃเซ€ เชตเชพเชฐ เชœเชฐเซ‚เชฐ เชชเชกเซ‡ เช›เซ‡.

SQL HowTo: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹

เช† เชฒเซ‡เช–เชฎเชพเช‚ เช†เชชเชฃเซ‡ เช†เชตเซ€ เชธเชฎเชธเซเชฏเชพเชจเชพ "เชจเชฟเชทเซเช•เชชเชŸ" เช‰เช•เซ‡เชฒ, "เชธเซเชฎเชพเชฐเซเชŸ" เช…เชจเซ‡ เช–เซ‚เชฌ เชœ เชœเชŸเชฟเชฒ เช…เชฒเซเช—เซ‹เชฐเชฟเชงเชฎเชจเชพ PostgreSQL เชฎเชพเช‚ เช…เชฎเชฒเซ€เช•เชฐเชฃเชจเซ‡ เชœเซ‹เชˆเชถเซเช‚. เชฎเชณเซ‡เชฒเชพ เชกเซ‡เชŸเชพเชฎเชพเช‚เชฅเซ€ เชฌเชนเชพเชฐ เชจเซ€เช•เชณเชตเชพเชจเซ€ เชธเซเชฅเชฟเชคเชฟ เชธเชพเชฅเซ‡ SQL เชฎเชพเช‚ โ€œเชฒเซ‚เชชโ€, เชœเซ‡ เชธเชพเชฎเชพเชจเซเชฏ เชตเชฟเช•เชพเชธ เชฎเชพเชŸเซ‡ เช…เชจเซ‡ เช…เชจเซเชฏ เชธเชฎเชพเชจ เช•เซ‡เชธเซ‹เชฎเชพเช‚ เช‰เชชเชฏเซ‹เช— เชฎเชพเชŸเซ‡ เชฌเช‚เชจเซ‡ เช‰เชชเชฏเซ‹เช—เซ€ เชฅเชˆ เชถเช•เซ‡ เช›เซ‡.

เชšเชพเชฒเซ‹ เชเช• เชŸเซ‡เชธเซเชŸ เชกเซ‡เชŸเชพ เชธเซ‡เชŸ เชฒเชˆเช เช…เช—เชพเช‰เชจเซ‹ เชฒเซ‡เช–. เชœเซเชฏเชพเชฐเซ‡ เชธเซ‰เชฐเซเชŸ เช•เชฐเซ‡เชฒ เชฎเซ‚เชฒเซเชฏเซ‹ เชเช•เชฐเซ‚เชช เชฅเชพเชฏ เชคเซเชฏเชพเชฐเซ‡ เชชเซเชฐเชฆเชฐเซเชถเชฟเชค เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ‡ เชธเชฎเชฏ เชธเชฎเชฏ เชชเชฐ "เชœเชฎเซเชชเชฟเช‚เช—" เช•เชฐเชคเชพ เช…เชŸเช•เชพเชตเชตเชพ เชฎเชพเชŸเซ‡, เชชเซเชฐเชพเชฅเชฎเชฟเช• เช•เซ€ เช‰เชฎเซ‡เชฐเซ€เชจเซ‡ เชตเชฟเชทเชฏ เช…เชจเซเช•เซเชฐเชฎเชฃเชฟเช•เชพ เชตเชฟเชธเซเชคเซƒเชค เช•เชฐเซ‹. เชคเซ‡ เชœ เชธเชฎเชฏเซ‡, เช† เชคเชฐเชค เชœ เชคเซ‡เชจเซ‡ เชตเชฟเชถเชฟเชทเซเชŸเชคเชพ เช†เชชเชถเซ‡ เช…เชจเซ‡ เช…เชฎเชจเซ‡ เช–เชพเชคเชฐเซ€ เช†เชชเชถเซ‡ เช•เซ‡ เชธเซ‰เชฐเซเชŸเชฟเช‚เช— เช“เชฐเซเชกเชฐ เช…เชธเซเชชเชทเซเชŸ เช›เซ‡:

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

เชœเซ‡เชฎ เชคเซ‡ เชธเชพเช‚เชญเชณเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เชคเซ‡เชฎ เชคเซ‡ เชฒเช–เชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡

เชชเซเชฐเชฅเชฎ, เชšเชพเชฒเซ‹ เชตเชฟเชจเช‚เชคเซ€เชจเชพ เชธเซŒเชฅเซ€ เชธเชฐเชณ เชธเช‚เชธเซเช•เชฐเชฃเชจเซเช‚ เชธเซเช•เซ‡เชš เช•เชฐเซ€เช, เชฐเชœเซ‚เช†เชค เช•เชฐเชจเชพเชฐเชพเช“เชจเชพ ID เชจเซ‡ เชชเชธเชพเชฐ เช•เชฐเซ€เช เช‡เชจเชชเซเชŸ เชชเชฐเชฟเชฎเชพเชฃ เชคเชฐเซ€เช•เซ‡ เชเชฐเซ‡:

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: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹
[explan.tensor.ru เชชเชฐ เชœเซเช“]

เชฅเซ‹เชกเซเช‚ เช‰เชฆเชพเชธเซ€ - เช…เชฎเซ‡ เชซเช•เซเชค 20 เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ‹ เช“เชฐเซเชกเชฐ เช†เชชเซเชฏเซ‹ เชนเชคเซ‹, เชชเชฐเช‚เชคเซ เช‡เชจเซเชกเซ‡เช•เซเชธ เชธเซเช•เซ‡เชจ เช…เชฎเชจเซ‡ เชคเซ‡ เชชเชพเช›เซ‹ เชซเชฐเซเชฏเซ‹ 960 เชฐเซ‡เช–เชพเช“, เชœเซ‡ เชชเช›เซ€ เชชเชฃ เชธเซ‰เชฐเซเชŸ เช•เชฐเชตเชพเชจเซ€ เชนเชคเซ€... เชšเชพเชฒเซ‹ เช“เช›เซเช‚ เชตเชพเช‚เชšเชตเชพเชจเซ‹ เชชเซเชฐเชฏเชคเซเชจ เช•เชฐเซ€เช.

เช…เชจเชจเซ‡เชธเซเชŸ + ARRAY

เชœเซ‹ เช†เชชเชฃเชจเซ‡ เชœเชฐเซ‚เชฐ เชนเซ‹เชฏ เชคเซ‹ เชชเซเชฐเชฅเชฎ เชตเชฟเชšเชพเชฐเชฃเชพ เชœเซ‡ เช†เชชเชฃเชจเซ‡ เชฎเชฆเชฆ เช•เชฐเชถเซ‡ เชฎเชพเชคเซเชฐ 20 เช•เซเชฐเชฎเชพเช‚เช•เชฟเชค เชฐเซ‡เช•เซ‹เชฐเซเชก, เชชเช›เซ€ เชซเช•เซเชค เชตเชพเช‚เชšเซ‹ เชฆเชฐเซ‡เช• เชฎเชพเชŸเซ‡ เชธเชฎเชพเชจ เช•เซเชฐเชฎเชฎเชพเช‚ 20 เชฅเซ€ เชตเชงเซ เชจเชนเซ€เช‚ เชšเชพเชตเซ€ เชธเชพเชฐเซเช‚, เชฏเซ‹เช—เซเชฏ เช…เชจเซเช•เซเชฐเชฎเชฃเชฟเช•เชพ (owner_id, task_date, id) เช…เชฎเชพเชฐเซ€ เชชเชพเชธเซ‡ เช›เซ‡.

เชšเชพเชฒเซ‹ เชเช•เซเชธเซเชŸเซเชฐเซ‡เช•เซเชŸ เช•เชฐเชตเชพ เช…เชจเซ‡ "เช•เซ‰เชฒเชฎเซเชธเชฎเชพเช‚ เชซเซ‡เชฒเชพเชตเชตเชพ" เชฎเชพเชŸเซ‡ เชธเชฎเชพเชจ เชชเชฆเซเชงเชคเชฟเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เช. เช…เชญเชฟเชจเซเชจ เชŸเซ‡เชฌเชฒ เชฐเซ‡เช•เซ‹เชฐเซเชก, เชคเชฐเซ€เช•เซ‡ เช›เซ‡เชฒเซเชฒเชพ เชฒเซ‡เช–. เช†เชชเชฃเซ‡ เชซเช‚เช•เซเชถเชจเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชเชฐเซ‡เชฎเชพเช‚ เชซเซ‹เชฒเซเชกเชฟเช‚เช— เชชเชฃ เชฒเชพเช—เซ เช•เชฐเซ€ เชถเช•เซ€เช เช›เซ€เช 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: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹
[explan.tensor.ru เชชเชฐ เชœเซเช“]

เช“เชน, เชชเชนเซ‡เชฒเซ‡เชฅเซ€ เชœ เช˜เชฃเซเช‚ เชธเชพเชฐเซเช‚! 40% เชเชกเชชเซ€ เช…เชจเซ‡ 4.5 เช—เชฃเซ‹ เช“เช›เซ‹ เชกเซ‡เชŸเชพ เชฎเชพเชฐเซ‡ เชคเซ‡ เชตเชพเช‚เชšเชตเซเช‚ เชนเชคเซเช‚.

CTE เชฆเซเชตเชพเชฐเชพ เชŸเซ‡เชฌเชฒ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเซเช‚ เชญเซŒเชคเชฟเช•เซ€เช•เชฐเชฃเชšเชพเชฒเซ‹ เชนเซเช‚ เชคเชฎเชพเชฐเซเช‚ เชงเซเชฏเชพเชจ เช เชนเช•เซ€เช•เชค เชคเชฐเชซ เชฆเซ‹เชฐเซเช‚ เช•เซ‡ เช•เซ‡เชŸเชฒเชพเช• เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚ เชธเชฌเช•เซเชตเซ‡เชฐเซ€ เชฎเชพเช‚ เชคเซ‡เชจเซ‡ เชถเซ‹เชงเซเชฏเชพ เชชเช›เซ€ เชคเชฐเชค เชœ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเชพ เช•เซเชทเซ‡เชคเซเชฐเซ‹ เชธเชพเชฅเซ‡ เช•เชพเชฎ เช•เชฐเชตเชพเชจเซ‹ เชชเซเชฐเชฏเชพเชธ, เชคเซ‡เชจเซ‡ 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 เชฎเชพเช‚ "เชฒเชชเซ‡เชŸเซ€" เชฐเชพเช–เชตเซเช‚, เชœเซ‡ เช† เชธเช‚เชธเซเช•เชฐเชฃเซ‹เชฎเชพเช‚ เช‘เชชเซเชŸเชฟเชฎเชพเช‡เชเชฐ เชฎเชพเชŸเซ‡ เชšเซ‹เช•เซเช•เชธ เชฎเชฐเซเชฏเชพเชฆเชพ เช›เซ‡.

เชชเซเชจเชฐเชพเชตเชฐเซเชคเชฟเชค เชธเช‚เชšเชฏเช•

เช…เช—เชพเช‰เชจเชพ เชธเช‚เชธเซเช•เชฐเชฃเชฎเชพเช‚, เช†เชชเชฃเซ‡ เช•เซเชฒ เชตเชพเช‚เชšเซ€เช เช›เซ€เช 200 เชฐเซ‡เช–เชพเช“ เชœเชฐเซ‚เชฐเซ€ เช–เชพเชคเชฐ 20. 960 เชจเชนเซ€เช‚, เชชเชฃ เช“เช›เซเช‚ - เชถเซเช‚ เชคเซ‡ เชถเช•เซเชฏ เช›เซ‡?

เชšเชพเชฒเซ‹ เช†เชชเชฃเซ‡ เชœเชฐเซ‚เชฐเซ€ เชœเซเชžเชพเชจเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชจเซ‹ เชชเซเชฐเชฏเชพเชธ เช•เชฐเซ€เช เช•เซเชฒ 20 เชฐเซ‡เช•เซ‹เชฐเซเชก เชเชŸเชฒเซ‡ เช•เซ‡, เช…เชฎเซ‡ เชœเชฐเซ‚เชฐเซ€ เชฐเช•เชฎ เชธเซเชงเซ€ เชชเชนเซ‹เช‚เชšเซ€เช เชคเซเชฏเชพเช‚ เชธเซเชงเซ€ เชœ เช…เชฎเซ‡ เชกเซ‡เชŸเชพ เชฐเซ€เชกเชฟเช‚เช—เชจเซเช‚ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชจ เช•เชฐเซ€เชถเซเช‚.

เชชเช—เชฒเซเช‚ 1: เชถเชฐเซ‚เช†เชคเชจเซ€ เชธเซ‚เชšเชฟ

เชฆเซ‡เช–เซ€เชคเซ€ เชฐเซ€เชคเซ‡, 20 เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ€ เช…เชฎเชพเชฐเซ€ "เชฒเช•เซเชทเซเชฏ" เชธเซ‚เชšเชฟ เช…เชฎเชพเชฐเซ€ เชฎเชพเชฒเชฟเช•_เช†เช‡เชกเซ€ เช•เซ€เชฎเชพเช‚เชฅเซ€ เชเช• เชฎเชพเชŸเซ‡ "เชชเซเชฐเชฅเชฎ" เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชฅเซ€ เชถเชฐเซ‚ เชฅเชตเซ€ เชœเซ‹เชˆเช. เชคเซ‡เชฅเซ€, เชชเซเชฐเชฅเชฎ เช†เชชเชฃเซ‡ เช†เชตเชพ เชถเซ‹เชงเซ€เชถเซเช‚ เชฆเชฐเซ‡เช• เช•เซ€ เชฎเชพเชŸเซ‡ "เช–เซ‚เชฌ เชœ เชชเซเชฐเชฅเชฎ". เช…เชจเซ‡ เชคเซ‡เชจเซ‡ เช…เชฎเซ‡ เชœเซ‹เชˆเชคเชพ เช•เซเชฐเชฎเชฎเชพเช‚ เชธเซ‰เชฐเซเชŸ เช•เชฐเซ€เชจเซ‡ เชคเซ‡เชจเซ‡ เชธเซ‚เชšเชฟเชฎเชพเช‚ เช‰เชฎเซ‡เชฐเซ‹ - (task_date, id).

SQL HowTo: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹

เชชเช—เชฒเซเช‚ 2: "เช†เช—เชฒเซ€" เชเชจเซเชŸเซเชฐเซ€เช“ เชถเซ‹เชงเซ‹

เชนเชตเซ‡ เชœเซ‹ เช†เชชเชฃเซ‡ เช†เชชเชฃเซ€ เชฏเชพเชฆเซ€เชฎเชพเช‚เชฅเซ€ เชชเซเชฐเชฅเชฎ เชเชจเซเชŸเซเชฐเซ€ เชฒเชˆเช เช…เชจเซ‡ เชถเชฐเซ เช•เชฐเซ€เช เช…เชจเซเช•เซเชฐเชฎเชฃเชฟเช•เชพ เชธเชพเชฅเซ‡ "เชชเช—เชฒเซเช‚" เช†เช—เชณ เช“เชจเชฐ_เช†เชˆเชกเซ€ เช•เซ€ เชธเชพเชšเชตเซ€เชจเซ‡, เชชเช›เซ€ เชฎเชณเซ‡เชฒเชพ เชคเชฎเชพเชฎ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชชเชฐเชฟเชฃเชพเชฎเซ€ เชชเชธเช‚เชฆเช—เซ€เชฎเชพเช‚ เชฌเชฐเชพเชฌเชฐ เชชเช›เซ€เชจเชพ เช›เซ‡. เช…เชฒเชฌเชคเซเชค, เชฎเชพเชคเซเชฐ เชœเซเชฏเชพเช‚ เชธเซเชงเซ€ เช†เชชเชฃเซ‡ เชฌเชŸ เช•เซ€ เชชเชพเชฐ เชจ เช•เชฐเซ€เช เชฏเชพเชฆเซ€เชฎเชพเช‚ เชฌเซ€เชœเซ€ เชเชจเซเชŸเซเชฐเซ€.

เชœเซ‹ เชคเซ‡ เชคเชพเชฐเชฃ เช†เชชเซ‡ เช›เซ‡ เช•เซ‡ เช…เชฎเซ‡ เชฌเซ€เชœเชพ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเซ‡ "เช“เชณเช‚เช—" เช•เชฐเซเชฏเซ‹ เช›เซ‡, เชคเซ‹ เชชเช›เซ€ เชตเชพเช‚เชšเซ‡เชฒเซ€ เช›เซ‡เชฒเซเชฒเซ€ เชเชจเซเชŸเซเชฐเซ€ เชชเซเชฐเชฅเชฎเชจเซ‡ เชฌเชฆเชฒเซ‡ เชฏเชพเชฆเซ€เชฎเชพเช‚ เช‰เชฎเซ‡เชฐเชตเซ€ เชœเซ‹เชˆเช (เชธเชฎเชพเชจ เชฎเชพเชฒเชฟเช•_id เชธเชพเชฅเซ‡), เชœเซ‡ เชชเช›เซ€ เช…เชฎเซ‡ เชธเซ‚เชšเชฟเชจเซ‡ เชซเชฐเซ€เชฅเซ€ เชธเซ‰เชฐเซเชŸ เช•เชฐเซ€เช เช›เซ€เช.

SQL HowTo: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹

เชเชŸเชฒเซ‡ เช•เซ‡, เช…เชฎเซ‡ เชนเช‚เชฎเซ‡เชถเชพ เชฎเซ‡เชณเชตเซ€เช เช›เซ€เช เช•เซ‡ เชธเซ‚เชšเชฟเชฎเชพเช‚ เชฆเชฐเซ‡เช• เช•เซ€ เชฎเชพเชŸเซ‡ เชเช• เช•เชฐเชคเชพเช‚ เชตเชงเซ เชเชจเซเชŸเซเชฐเซ€ เชจเชฅเซ€ (เชœเซ‹ เชเชจเซเชŸเซเชฐเซ€เช“ เชธเชฎเชพเชชเซเชค เชฅเชˆ เชœเชพเชฏ เช…เชจเซ‡ เช…เชฎเซ‡ "เช•เซเชฐเซ‹เชธ" เชจ เช•เชฐเซ€เช, เชคเซ‹ เชธเซ‚เชšเชฟเชฎเชพเช‚เชฅเซ€ เชชเซเชฐเชฅเชฎ เชเชจเซเชŸเซเชฐเซ€ เช–เชพเชฒเซ€ เช…เชฆเซƒเชถเซเชฏ เชฅเชˆ เชœเชถเซ‡ เช…เชจเซ‡ เช•เช‚เชˆเชชเชฃ เช‰เชฎเซ‡เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡ เชจเชนเซ€เช‚. ), เช…เชจเซ‡ เชคเซ‡เช“ เชนเช‚เชฎเซ‡เชถเชพ เช•เซเชฐเชฎเชพเช‚เช•เชฟเชค เชเชชเซเชฒเชฟเช•เซ‡เชถเชจ เช•เซ€เชจเชพ เชšเชกเชคเชพ เช•เซเชฐเชฎเชฎเชพเช‚ (task_date, id).

SQL HowTo: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹

เชชเช—เชฒเซเช‚ 3: เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ‡ เชซเชฟเชฒเซเชŸเชฐ เช•เชฐเซ‹ เช…เชจเซ‡ "เชตเชฟเชธเซเชคเซƒเชค เช•เชฐเซ‹".

เช…เชฎเชพเชฐเซ€ เชชเซเชจเชฐเชพเชตเชฐเซเชคเชฟเชค เชชเชธเช‚เชฆเช—เซ€เชจเซ€ เช•เซ‡เชŸเชฒเซ€เช• เชชเช‚เช•เซเชคเชฟเช“เชฎเชพเช‚, เช•เซ‡เชŸเชฒเชพเช• เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ 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: เช•เซเชตเซ‡เชฐเซ€ เช…เชฅเชตเชพ "เชชเซเชฐเชพเชฅเชฎเชฟเช• เชฅเซเชฐเซ€-เชตเซ‡"เชฎเชพเช‚ เชธเซ€เชงเชพ เชœ เชœเซเชฏเชพเชฐเซ‡-เชฒเซ‚เชช เชฒเช–เซ‹
[explan.tensor.ru เชชเชฐ เชœเซเช“]

เช†เชฎ, เช…เชฎเซ‡ เชเช•เซเชเซ‡เช•เซเชฏเซเชถเชจ เชธเชฎเชฏเชจเชพ 50% เชฎเชพเชŸเซ‡ 20% เชกเซ‡เชŸเชพ เชตเชพเช‚เชšเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡. เชเชŸเชฒเซ‡ เช•เซ‡, เชœเซ‹ เชคเชฎเชพเชฐเซ€ เชชเชพเชธเซ‡ เชเชตเซเช‚ เชฎเชพเชจเชตเชพเชจเชพเช‚ เช•เชพเชฐเชฃเซ‹ เช›เซ‡ เช•เซ‡ เชตเชพเช‚เชšเชตเชพเชฎเชพเช‚ เช˜เชฃเซ‹ เชธเชฎเชฏ เชฒเชพเช—เซ€ เชถเช•เซ‡ เช›เซ‡ (เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชกเซ‡เชŸเชพ เช˜เชฃเซ€เชตเชพเชฐ เช•เซ‡เชถเชฎเชพเช‚ เชจเชฅเซ€, เช…เชจเซ‡ เชคเชฎเชพเชฐเซ‡ เชคเซ‡เชจเชพ เชฎเชพเชŸเซ‡ เชกเชฟเชธเซเช• เชชเชฐ เชœเชตเซเช‚ เชชเชกเชถเซ‡), เชคเซ‹ เช† เชฐเซ€เชคเซ‡ เชคเชฎเซ‡ เชตเชพเช‚เชšเชจ เชชเชฐ เช“เช›เซ‹ เช†เชงเชพเชฐ เชฐเชพเช–เซ€ เชถเช•เซ‹ เช›เซ‹. .

เช•เซ‹เชˆ เชชเชฃ เชธเช‚เชœเซ‹เช—เซ‹เชฎเชพเช‚, เช…เชฎเชฒเชจเซ‹ เชธเชฎเชฏ "เชจเชฟเชทเซเช•เชชเชŸ" เชชเซเชฐเชฅเชฎ เชตเชฟเช•เชฒเซเชช เช•เชฐเชคเชพเช‚ เชตเชงเซ เชธเชพเชฐเซ‹ เชนเชคเซ‹. เชชเชฐเช‚เชคเซ เช† 3 เชตเชฟเช•เชฒเซเชชเซ‹เชฎเชพเช‚เชฅเซ€ เช•เชฏเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเซ‹ เชคเซ‡ เชคเชฎเชพเชฐเชพ เชชเชฐ เชจเชฟเชฐเซเชญเชฐ เช›เซ‡.

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹