SQL เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"

เด†เดจเตเด•เดพเดฒเดฟเด•เดฎเดพเดฏเดฟ, เด’เดฐเต เด•เต‚เดŸเตเดŸเด‚ เด•เต€เด•เตพ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เด…เดจเตเดฌเดจเตเดง เดกเดพเดฑเตเดฑ เดคเดฟเดฐเดฏเตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เดšเตเดฎเดคเดฒ เด‰เดฏเตผเดจเตเดจเตเดตเดฐเตเดจเตเดจเต. เด†เดตเดถเตเดฏเดฎเดพเดฏ เดฎเตŠเดคเตเดคเด‚ เดฑเต†เด•เตเด•เต‹เตผเดกเตเด•เดณเตเดŸเต† เดŽเดฃเตเดฃเด‚ เดฒเดญเดฟเด•เตเด•เตเดจเตเดจเดคเตเดตเดฐเต†.

เดเดฑเตเดฑเดตเตเด‚ "เดฏเดฅเดพเตผเดคเตเดฅ เดœเต€เดตเดฟเดค" เด‰เดฆเดพเดนเดฐเดฃเด‚ เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเด•เตเด•เตเด• เดŽเดจเตเดจเดคเดพเดฃเต 20 เดเดฑเตเดฑเดตเตเด‚ เดชเดดเดฏ เดชเตเดฐเดถเตเดจเด™เตเด™เตพ, เดชเดŸเตเดŸเดฟเด•เดชเตเดชเต†เดŸเตเดคเตเดคเดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต เดœเต€เดตเดจเด•เตเด•เดพเดฐเตเดŸเต† เดชเดŸเตเดŸเดฟเด•เดฏเดฟเตฝ (เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เด’เดฐเต เดกเดฟเดตเดฟเดทเดจเดฟเตฝ). เดคเตŠเดดเดฟเตฝ เดฎเต‡เด–เดฒเด•เดณเตเดŸเต† เดธเด‚เด•เตเดทเดฟเดชเตเดค เดธเด‚เด—เตเดฐเดนเด™เตเด™เดณเตเดณเตเดณ เดตเดฟเดตเดฟเดง เดฎเดพเดจเต‡เดœเตเดฎเต†เดจเตเดฑเต "เดกเดพเดทเตเดฌเต‹เตผเดกเตเด•เตพเด•เตเด•เต", เดธเดฎเดพเดจเดฎเดพเดฏ เด’เดฐเต เดตเดฟเดทเดฏเด‚ เดชเดฒเดชเตเดชเต‹เดดเตเด‚ เด†เดตเดถเตเดฏเดฎเดพเดฃเต.

SQL เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"

เดˆ เดฒเต‡เด–เดจเดคเตเดคเดฟเตฝ เดจเดฎเตเดฎเตพ PostgreSQL-เตฝ เด‡เดคเตเดคเดฐเดฎเตŠเดฐเต เดชเตเดฐเดถเตเดจเดคเตเดคเดฟเดจเตเดณเตเดณ "เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ" เดชเดฐเดฟเดนเดพเดฐเด‚, "เดธเตเดฎเดพเตผเดŸเตเดŸเตผ", เดตเดณเดฐเต† เดธเด™เตเด•เต€เตผเดฃเตเดฃเดฎเดพเดฏ เด…เตฝเด—เต‹เดฐเดฟเดคเด‚ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต เดจเต‹เด•เตเด•เดพเด‚. เด•เดฃเตเดŸเต†เดคเตเดคเดฟเดฏ เดกเดพเดฑเตเดฑเดฏเดฟเตฝ เดจเดฟเดจเตเดจเต เด’เดฐเต เดŽเด•เตเดธเดฟเดฑเตเดฑเต เดตเตเดฏเดตเดธเตเดฅเดฏเต‹เดŸเต† SQL-เตฝ "เดฒเต‚เดชเตเดชเต", เด‡เดคเต เดชเตŠเดคเตเดตเดพเดฏ เดตเดฟเด•เดธเดจเดคเตเดคเดฟเดจเตเด‚ เดธเดฎเดพเดจเดฎเดพเดฏ เดฎเดฑเตเดฑเต เดธเดจเตเดฆเตผเดญเด™เตเด™เดณเดฟเตฝ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเดจเตเด‚ เด‰เดชเดฏเต‹เด—เดชเตเดฐเดฆเดฎเดพเด•เตเด‚.

เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดŸเต†เดธเตเดฑเตเดฑเต เดกเดพเดฑเตเดฑ เดธเต†เดฑเตเดฑเต เดŽเดŸเตเด•เตเด•เดพเด‚ เดฎเตเตป เดฒเต‡เด–เดจเด‚. เด•เตเดฐเดฎเต€เด•เดฐเดฟเดšเตเดš เดฎเต‚เดฒเตเดฏเด™เตเด™เตพ เดชเตŠเดฐเตเดคเตเดคเดชเตเดชเต†เดŸเตเดฎเตเดชเต‹เตพ, เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเดšเตเดš เดฑเต†เด•เตเด•เต‹เตผเดกเตเด•เตพ เด•เดพเดฒเดพเด•เดพเดฒเด™เตเด™เดณเดฟเตฝ "เดšเดพเดŸเดฟ" เดคเดŸเดฏเตเดจเตเดจเดคเดฟเดจเต, เด’เดฐเต เดชเตเดฐเดพเดฅเดฎเดฟเด• เด•เต€ เดšเต‡เตผเดคเตเดคเตเด•เตŠเดฃเตเดŸเต เดตเดฟเดทเดฏ เดธเต‚เดšเดฟเด• เดตเดฟเด•เดธเดฟเดชเตเดชเดฟเด•เตเด•เตเด•. เด…เดคเต‡ เดธเดฎเดฏเด‚, เด‡เดคเต เด‰เดŸเดจเดŸเดฟ เด…เดคเดฟเดจเต เด…เดฆเตเดตเดฟเดคเต€เดฏเดค เดจเตฝเด•เตเด•เดฏเตเด‚ เดธเต‹เตผเดŸเตเดŸเดฟเด‚เด—เต เด“เตผเดกเตผ เด…เดตเตเดฏเด•เตเดคเดฎเดพเดฃเต†เดจเตเดจเต เดžเด™เตเด™เตพเด•เตเด•เต เด‰เดฑเดชเตเดชเต เดจเตฝเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเด‚:

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

เด•เต‡เดŸเตเดŸเดคเตเดชเต‹เดฒเต† เดŽเดดเตเดคเดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต

เด†เดฆเตเดฏเด‚, เด…เดญเตเดฏเตผเดคเตเดฅเดจเดฏเตเดŸเต† เดเดฑเตเดฑเดตเตเด‚ เดฒเดณเดฟเดคเดฎเดพเดฏ เดชเดคเดฟเดชเตเดชเต เดตเดฐเดฏเตเด•เตเด•เดพเด‚, เดชเตเดฐเด•เดŸเดจเด‚ เดจเดŸเดคเตเดคเตเดจเตเดจเดตเดฐเตเดŸเต† เดเดกเดฟเด•เตพ เด•เตˆเดฎเดพเดฑเตเด• เด‡เตปเดชเตเดŸเตเดŸเต เดชเดพเดฐเดพเดฎเต€เดฑเตเดฑเดฑเดพเดฏเดฟ เด…เดฑเต‡:

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 เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"
[explain.tensor.ru-เตฝ เด•เดพเดฃเตเด•]

เด…เตฝเดชเตเดชเด‚ เดธเด™เตเด•เดŸเด‚ - เดžเด™เตเด™เตพ 20 เดฑเต†เด•เตเด•เต‹เตผเดกเตเด•เตพ เดฎเดพเดคเตเดฐเดฎเต‡ เด“เตผเดกเตผ เดšเต†เดฏเตเดคเดฟเดŸเตเดŸเตเดณเตเดณเต‚, เดชเด•เตเดทเต‡ เด‡เตปเดกเด•เตเดธเต เดธเตเด•เดพเตป เด…เดคเต เดžเด™เตเด™เตพเด•เตเด•เต เดคเดฟเดฐเดฟเด•เต† เดจเตฝเด•เดฟ 960 เดตเดฐเดฟเด•เตพ, เด…เดคเตเด‚ เด…เดŸเตเด•เตเด•เต‡เดฃเตเดŸเดฟ เดตเดจเตเดจเต... เด•เตเดฑเดšเตเดšเต เดตเดพเดฏเดฟเด•เตเด•เดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เดพเด‚.

unnest + 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 เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"
[explain.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 เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"

เด˜เดŸเตเดŸเด‚ 2: "เด…เดŸเตเดคเตเดคเดคเต" เดŽเตปเดŸเตเดฐเดฟเด•เตพ เด•เดฃเตเดŸเต†เดคเตเดคเตเด•

เด‡เดจเดฟ เดจเดฎเตเดฎเตเดŸเต† เดฒเดฟเดธเตเดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเตเด‚ เด†เดฆเตเดฏ เดŽเตปเดŸเตเดฐเดฟ เดŽเดŸเตเดคเตเดคเต เดคเตเดŸเด™เตเด™เตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ เดธเต‚เดšเดฟเด•เดฏเต‹เดŸเตŠเดชเตเดชเด‚ "เดชเดŸเดฟ" owner_id เด•เต€ เดธเด‚เดฐเด•เตเดทเดฟเด•เตเด•เตเดจเตเดจเต, เดคเตเดŸเตผเดจเตเดจเต เด•เดฃเตเดŸเต†เดคเตเดคเดฟเดฏ เดŽเดฒเตเดฒเดพ เดฐเต‡เด–เด•เดณเตเด‚ เดซเดฒเดฎเดพเดฏเตเดฃเตเดŸเดพเด•เตเดจเตเดจ เดคเดฟเดฐเดžเตเดžเต†เดŸเตเดชเตเดชเดฟเดฒเต† เด…เดŸเตเดคเตเดคเดตเดฏเดพเดฃเต. เดคเต€เตผเดšเตเดšเดฏเดพเดฏเตเด‚, เดฎเดพเดคเตเดฐเด‚ เดžเด™เตเด™เตพ เดฌเดŸเตเดŸเต เด•เต€ เด•เดŸเด•เตเด•เตเดจเตเดจเดคเตเดตเดฐเต† เดชเดŸเตเดŸเดฟเด•เดฏเดฟเดฒเต† เดฐเดฃเตเดŸเดพเดฎเดคเตเดคเต† เดŽเตปเดŸเตเดฐเดฟ.

เดžเด™เตเด™เตพ เดฐเดฃเตเดŸเดพเดฎเดคเตเดคเต† เดฑเต†เด•เตเด•เต‹เตผเดกเต "เด•เดŸเดจเตเดจเต" เดŽเดจเตเดจเต เดฎเดพเดฑเตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ, เดชเดฟเดจเตเดจเต† เด†เดฆเตเดฏเดคเตเดคเต‡เดคเดฟเดจเต เดชเด•เดฐเด‚ เด…เดตเดธเดพเดจเด‚ เดตเดพเดฏเดฟเดšเตเดš เดŽเตปเดŸเตเดฐเดฟ เดชเดŸเตเดŸเดฟเด•เดฏเดฟเตฝ เดšเต‡เตผเด•เตเด•เดฃเด‚ (เด…เดคเต‡ เด‰เดŸเดฎเดธเตเดฅเตป_เดเดกเดฟเด•เตเด•เตŠเดชเตเดชเด‚), เด…เดคเดฟเดจเตเดถเต‡เดทเด‚ เดžเด™เตเด™เตพ เดฒเดฟเดธเตเดฑเตเดฑเต เดตเต€เดฃเตเดŸเตเด‚ เด…เดŸเตเด•เตเด•เตเดจเตเดจเต.

SQL เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"

เด…เดคเดพเดฏเดคเต, เด“เดฐเต‹ เด•เต€เด•เตพเด•เตเด•เตเด‚ เดฒเดฟเดธเตเดฑเตเดฑเดฟเตฝ เด’เดจเตเดจเดฟเตฝ เด•เต‚เดŸเตเดคเตฝ เดŽเตปเดŸเตเดฐเดฟเด•เตพ เด‡เดฒเตเดฒเต†เดจเตเดจเต เดžเด™เตเด™เตพเด•เตเด•เต เดŽเดฒเตเดฒเดพเดฏเตเดชเตเดชเต‹เดดเตเด‚ เดฒเดญเดฟเด•เตเด•เตเดจเตเดจเต (เดŽเตปเดŸเตเดฐเดฟเด•เตพ เดคเต€เตผเดจเตเดจเต เดžเด™เตเด™เตพ "เด•เตเดฐเต‹เดธเต" เดšเต†เดฏเตเดฏเตเดจเตเดจเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เดฒเดฟเดธเตเดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เด†เดฆเตเดฏ เดŽเตปเดŸเตเดฐเดฟ เด…เดชเตเดฐเดคเตเดฏเด•เตเดทเดฎเดพเด•เตเด‚ เด•เต‚เดŸเดพเดคเต† เด’เดจเตเดจเตเด‚ เดšเต‡เตผเด•เตเด•เดฟเดฒเตเดฒ ), เดชเดฟเดจเตเดจเต† เด…เดตเตผ เดŽเดชเตเดชเต‹เดดเตเด‚ เด…เดŸเตเด•เตเด•เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต เด†เดชเตเดฒเดฟเด•เตเด•เต‡เดทเตป เด•เต€เดฏเตเดŸเต† เด†เดฐเต‹เดนเดฃ เด•เตเดฐเดฎเดคเตเดคเดฟเตฝ (task_date, id).

SQL เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"

เด˜เดŸเตเดŸเด‚ 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 เดŽเด™เตเด™เดจเต†: เดšเต‹เดฆเตเดฏเดคเตเดคเดฟเตฝ เดจเต‡เดฐเดฟเดŸเตเดŸเต เด’เดฐเต เดฒเต‚เดชเตเดชเต เดŽเดดเตเดคเตเด•, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ "เดŽเดฒเดฟเดฎเต†เดจเตเดฑเดฑเดฟ เดคเตเดฐเต€-เดธเตเดฑเตเดฑเต†เดชเตเดชเต"
[explain.tensor.ru-เตฝ เด•เดพเดฃเตเด•]

เด…เด™เตเด™เดจเต†, เดžเด™เตเด™เตพ เดŽเด•เตโ€Œเดธเดฟเด•เตเดฏเต‚เดทเตป เดธเดฎเดฏเดคเตเดคเดฟเดจเตเดฑเต† 50% เดฑเต€เดกเตเด•เดณเตเดŸเต† 20% เดŸเตเดฐเต‡เดกเต เดšเต†เดฏเตเดคเต. เด…เดคเดพเดฏเดคเต, เดตเดพเดฏเดจเดฏเตเด•เตเด•เต เดตเดณเดฐเต†เดฏเดงเดฟเด•เด‚ เดธเดฎเดฏเดฎเต†เดŸเตเด•เตเด•เตเดฎเต†เดจเตเดจเต เดตเดฟเดถเตเดตเดธเดฟเด•เตเด•เดพเตป เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด•เดพเดฐเดฃเด™เตเด™เดณเตเดฃเตเดŸเต†เด™เตเด•เดฟเตฝ (เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เดกเดพเดฑเตเดฑ เดชเดฒเดชเตเดชเต‹เดดเตเด‚ เด•เดพเดทเต†เดฏเดฟเดฒเดพเดฏเดฟเดฐเดฟเด•เตเด•เดฟเดฒเตเดฒ, เด…เดคเดฟเดจเดพเดฏเดฟ เดจเดฟเด™เตเด™เตพ เดกเดฟเดธเตเด•เดฟเดฒเต‡เด•เตเด•เต เดชเต‹เด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต), เดˆ เดฐเต€เดคเดฟเดฏเดฟเตฝ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดตเดพเดฏเดจเดฏเต† เด•เตเดฑเดšเตเดšเต เด†เดถเตเดฐเดฏเดฟเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚. .

เดเดคเต เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเดฒเตเด‚, เดŽเด•เตเดธเดฟเด•เตเดฏเต‚เดทเตป เดธเดฎเดฏเด‚ "เดจเดฟเดทเตเด•เดณเด™เตเด•" เด†เดฆเตเดฏ เด“เดชเตเดทเดจเต‡เด•เตเด•เดพเตพ เดฎเดฟเด•เดšเตเดšเดคเดพเดฏเดฟ เดฎเดพเดฑเดฟ. เดŽเดจเตเดจเดพเตฝ เดˆ 3 เด“เดชเตเดทเดจเตเด•เดณเดฟเตฝ เดเดคเดพเดฃเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เต‡เดฃเตเดŸเดคเต เดŽเดจเตเดจเดคเต เดจเดฟเด™เตเด™เดณเตเดŸเต‡เดคเดพเดฃเต.

เด…เดตเดฒเด‚เดฌเด‚: www.habr.com

เด’เดฐเต เด…เดญเดฟเดชเตเดฐเดพเดฏเด‚ เดšเต‡เตผเด•เตเด•เตเด•