SQL HowTo: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"

рдЖрд╡рдзрд┐рдХ рд░реВрдкрдорд╛, рдХреБрдЮреНрдЬреАрд╣рд░реВрдХреЛ рд╕реЗрдЯ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рд╕рдореНрдмрдиреНрдзрд┐рдд рдбреЗрдЯрд╛ рдЦреЛрдЬреНрдиреЗ рдХрд╛рд░реНрдп рдЙрддреНрдкрдиреНрди рд╣реБрдиреНрдЫред рдЬрдмрд╕рдореНрдо рд╣рд╛рдореАрд▓реЗ рдЕрднрд┐рд▓реЗрдЦрд╣рд░реВрдХреЛ рдЖрд╡рд╢реНрдпрдХ рдХреБрд▓ рд╕рдВрдЦреНрдпрд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрджреИрдиреМрдВ.

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

SQL HowTo: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"

рдпрд╕ рд▓реЗрдЦрдорд╛ рд╣рд╛рдореА PostgreSQL рдорд╛ рдпрд╕реНрддреЛ рд╕рдорд╕реНрдпрд╛рдХреЛ рд▓рд╛рдЧрд┐ "рднреЛрд▓реА" рд╕рдорд╛рдзрд╛рдирдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирд▓рд╛рдИ рд╣реЗрд░реНрдиреЗрдЫреМрдВ, рдПрдХ "рдЪрддреБрд░" рд░ рдзреЗрд░реИ рдЬрдЯрд┐рд▓ рдПрд▓реНрдЧреЛрд░рд┐рджрдоред рдлреЗрд▓рд╛ рдкрд░реЗрдХреЛ рдбрд╛рдЯрд╛рдмрд╛рдЯ рдмрд╛рд╣рд┐рд░ рдирд┐рд╕реНрдХрдиреЗ рдЕрд╡рд╕реНрдерд╛рдХреЛ рд╕рд╛рде SQL рдорд╛ "рд▓реВрдк", рдЬреБрди рд╕рд╛рдорд╛рдиреНрдп рд╡рд┐рдХрд╛рд╕ рд░ рдЕрдиреНрдп рд╕рдорд╛рди рдЕрд╡рд╕реНрдерд╛рдорд╛ рдкреНрд░рдпреЛрдЧрдХреЛ рд▓рд╛рдЧрд┐ рджреБрд╡реИ рдЙрдкрдпреЛрдЧреА рд╣реБрди рд╕рдХреНрдЫред

рдмрд╛рдЯ рдкрд░реАрдХреНрд╖рдг рдбрд╛рдЯрд╛ рд╕реЗрдЯ рд▓рд┐рдиреБрд╣реЛрд╕реН рдЕрдШрд┐рд▓реНрд▓реЛ рд▓реЗрдЦред рдХреНрд░рдордмрджреНрдз рдорд╛рдирд╣рд░реВ рдорд┐рд▓реНрджрд╛ рд╕рдордп-рд╕рдордпрдорд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рд░реЗрдХрд░реНрдбрд╣рд░реВрд▓рд╛рдИ "рдЬрдореНрдкрд┐рдЩ" рдмрд╛рдЯ рд░реЛрдХреНрдирдХреЛ рд▓рд╛рдЧрд┐, рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдЮреНрдЬреА рдердкреЗрд░ рд╡рд┐рд╖рдп рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдЧрд░реНрдиреБрд╣реЛрд╕реНред рдПрдХреИ рд╕рдордпрдорд╛, рдпрд╕рд▓реЗ рддреБрд░реБрдиреНрддреИ рдпрд╕рд▓рд╛рдИ рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рджрд┐рдиреЗрдЫ рд░ рд╣рд╛рдореАрд▓рд╛рдИ рдЧреНрдпрд╛рд░реЗрдиреНрдЯреА рдЧрд░реНрдиреЗрдЫ рдХрд┐ рдХреНрд░рдордмрджреНрдз рдХреНрд░рдо рдЕрд╕реНрдкрд╖реНрдЯ рдЫ:

CREATE INDEX ON task(owner_id, task_date, id);
-- ╨░ ╤Б╤В╨░╤А╤Л╨╣ - ╤Г╨┤╨░╨╗╨╕╨╝
DROP INDEX task_owner_id_task_date_idx;

рдЬрд╕рд░реА рд╕реБрдирд┐рдиреНрдЫ, рддреНрдпрд╕реНрддреИ рд▓реЗрдЦрд┐рдиреНрдЫ

рдкрд╣рд┐рд▓реЗ, рдЕрдиреБрд░реЛрдзрдХреЛ рд╕рд░рд▓ рд╕рдВрд╕реНрдХрд░рдг рд╕реНрдХреЗрдЪ рдЧрд░реМрдВ, рдкреНрд░рджрд░реНрд╢рдирдХрд░реНрддрд╛рд╣рд░реВрдХреЛ рдЖрдИрдбреАрд╣рд░реВ рдкрд╛рд╕ рдЧрд░реНрджреИ рдЗрдирдкреБрдЯ рдкреНрдпрд╛рд░рд╛рдорд┐рдЯрд░рдХреЛ рд░реВрдкрдорд╛ 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: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"
[explan.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 HowTo: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рдУрд╣, рдкрд╣рд┐рд▓реЗ рдиреИ рдзреЗрд░реИ рд░рд╛рдореНрд░реЛ! рекреж% рдЫрд┐рдЯреЛ рд░ рек.рел рдЧреБрдгрд╛ рдХрдо рдбрд╛рдЯрд╛ рдкрдвреНрдиреБрдкрд░реНрдиреЗ рднрдпреЛ ред

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: "рдЕрд░реНрдХреЛ" рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рд╣рд░реВ рдлреЗрд▓рд╛ рдкрд╛рд░реНрдиреБрд╣реЛрд╕реН

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

рдпрджрд┐ рдпреЛ рдмрд╛рд╣рд┐рд░ рдЬрд╛рдиреНрдЫ рдХрд┐ рд╣рд╛рдореАрд▓реЗ рджреЛрд╕реНрд░реЛ рд░реЗрдХрд░реНрдб "рдХреНрд░рд╕" рдЧрд░реНрдпреМрдВ, рддреНрдпрд╕рдкрдЫрд┐ рдкрд╣рд┐рд▓реЛрдХреЛ рд╕рдЯреНрдЯрд╛ рдЕрдиреНрддрд┐рдо рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкрдврд┐рдПрдХреЛ рд╕реВрдЪреАрдорд╛ рдердкрд┐рдиреБрдкрд░реНрдЫ (рдЙрд╣реА рдорд╛рд▓рд┐рдХ_рдЖрдИрдбреА рд╕рдВрдЧ), рдЬрд╕ рдкрдЫрд┐ рд╣рд╛рдореА рд╕реВрдЪреА рдкреБрди: рдХреНрд░рдордмрджреНрдз рдЧрд░реНрдЫреМрдВред

SQL HowTo: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"

рддреНрдпреЛ рд╣реЛ, рд╣рд╛рдореАрд▓реЗ рд╕рдзреИрдВ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдЫреМрдВ рдХрд┐ рд╕реВрдЪреАрдорд╛ рдкреНрд░рддреНрдпреЗрдХ рдХреБрдЮреНрдЬреАрдХреЛ рд▓рд╛рдЧрд┐ рдПрдХ рднрдиреНрджрд╛ рдмрдвреА рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рд╣рд░реВ рдЫреИрдирдиреН (рдпрджрд┐ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рд╣рд░реВ рд╕рдорд╛рдкреНрдд рднрдП рд░ рд╣рд╛рдореАрд▓реЗ "рдХреНрд░рд╕" рдЧрд░реЗрдиреМрдВ рднрдиреЗ, рд╕реВрдЪреАрдмрд╛рдЯ рдкрд╣рд┐рд▓реЛ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдорд╛рддреНрд░ рдЧрд╛рдпрдм рд╣реБрдиреЗрдЫ рд░ рдХреЗрд╣рд┐ рдердкрд┐рдиреЗ рдЫреИрдиред ), рдЕрдирд┐ рддрд┐рдиреАрд╣рд░реБ рд╕рдзреИрдВ рдХреНрд░рдордмрджреНрдз рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреБрдЮреНрдЬреАрдХреЛ рдмрдвреНрджреЛ рдХреНрд░рдордорд╛ (task_date, id)ред

SQL HowTo: рдХреНрд╡реЗрд░реАрдорд╛ рд╕рд┐рдзреИ рдХреЗрд╣реА рд╕рдордп рд▓реБрдк рд▓реЗрдЦреНрджреИ, рд╡рд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рдЪрд░рдг"

рдЪрд░рдг 3: рдлрд┐рд▓реНрдЯрд░ рд░ "рд╡рд┐рд╕реНрддрд╛рд░" рд░реЗрдХрд░реНрдб

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

рдбрд░рд▓рд╛рдЧреНрджреЛ рдЕрдиреНрддрд┐рдо рдкреНрд░рд╢реНрди

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

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