рдореЗрд░реЛ рдХрд╛рдордХреЛ рдкреНрд░рдХреГрддрд┐рдХреЛ рдХрд╛рд░рдгрд▓реЗ рдЧрд░реНрджрд╛, рдореИрд▓реЗ рдкрд░рд┐рд╕реНрдерд┐рддрд┐рд╣рд░реВрдХреЛ рд╕рд╛рдордирд╛ рдЧрд░реНрдиреБрдкрд░реНрдЫ рдЬрдм рдПрдХ рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд▓реЗ рдЕрдиреБрд░реЛрдз рд▓реЗрдЦреНрдЫ рд░ рд╕реЛрдЪреНрджрдЫ "рдЖрдзрд╛рд░ рд╕реНрдорд╛рд░реНрдЯ рдЫ, рдпрд╕рд▓реЗ рд╕рдмреИ рдХреБрд░рд╛ рдЖрдлреИрдВ рд╣реНрдпрд╛рдиреНрдбрд▓ рдЧрд░реНрди рд╕рдХреНрдЫ!┬л

рдХреЗрд╣рд┐ рдЕрд╡рд╕реНрдерд╛рд╣рд░реВрдорд╛ (рдЖрдВрд╢рд┐рдХ рд░реВрдкрдорд╛ рдбрд╛рдЯрд╛рдмреЗрд╕рдХреЛ рдХреНрд╖рдорддрд╛рд╣рд░реВрдХреЛ рдЕрдЬреНрдЮрд╛рдирддрд╛рдмрд╛рдЯ, рдЖрдВрд╢рд┐рдХ рд░реВрдкрдорд╛ рд╕рдордпрдкреВрд░реНрд╡ рдЕрдкреНрдЯрд┐рдорд╛рдЗрдЬреЗрд╕рдирд╣рд░реВрдмрд╛рдЯ), рдпреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдгрд▓реЗ "рдлреНрд░рд╛рдиреНрдХреЗрдиреНрд╕реНрдЯрд╛рдЗрди" рдХреЛ рдЙрдкрд╕реНрдерд┐рддрд┐рдХреЛ рдиреЗрддреГрддреНрд╡ рдЧрд░реНрджрдЫред

рдкрд╣рд┐рд▓реЗ, рдо рдпрд╕реНрддреЛ рдЕрдиреБрд░реЛрдзрдХреЛ рдЙрджрд╛рд╣рд░рдг рджрд┐рдиреЗрдЫреБ:

-- ╨┤╨╗╤П ╨║╨░╨╢╨┤╨╛╨╣ ╨║╨╗╤О╤З╨╡╨▓╨╛╨╣ ╨┐╨░╤А╤Л ╨╜╨░╤Е╨╛╨┤╨╕╨╝ ╨░╤Б╤Б╨╛╤Ж╨╕╨╕╤А╨╛╨▓╨░╨╜╨╜╤Л╨╡ ╨╖╨╜╨░╤З╨╡╨╜╨╕╤П ╨┐╨╛╨╗╨╡╨╣
WITH RECURSIVE cte_bind AS (
  SELECT DISTINCT ON (key_a, key_b)
    key_a a
  , key_b b
  , fld1 bind_fld1
  , fld2 bind_fld2
  FROM
    tbl
)
-- ╨╜╨░╤Е╨╛╨┤╨╕╨╝ min/max ╨╖╨╜╨░╤З╨╡╨╜╨╕╨╣ ╨┤╨╗╤П ╨║╨░╨╢╨┤╨╛╨│╨╛ ╨┐╨╡╤А╨▓╨╛╨│╨╛ ╨║╨╗╤О╤З╨░
, cte_max AS (
  SELECT
    a
  , max(bind_fld1) bind_fld1
  , min(bind_fld2) bind_fld2
  FROM
    cte_bind
  GROUP BY
    a
)
-- ╤Б╨▓╤П╨╖╤Л╨▓╨░╨╡╨╝ ╨┐╨╛ ╨┐╨╡╤А╨▓╨╛╨╝╤Г ╨║╨╗╤О╤З╤Г ╨║╨╗╤О╤З╨╡╨▓╤Л╨╡ ╨┐╨░╤А╤Л ╨╕ min/max-╨╖╨╜╨░╤З╨╡╨╜╨╕╤П
, cte_a_bind AS (
  SELECT
    cte_bind.a
  , cte_bind.b
  , cte_max.bind_fld1
  , cte_max.bind_fld2
  FROM
    cte_bind
  INNER JOIN
    cte_max
      ON cte_max.a = cte_bind.a
)
SELECT * FROM cte_a_bind;

рдЕрдиреБрд░реЛрдзрдХреЛ рдЧреБрдгрд╕реНрддрд░рдХреЛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдореВрд▓реНрдпрд╛рдЩреНрдХрди рдЧрд░реНрди, рдХреЗрд╣реА рдордирдорд╛рдиреА рдбреЗрдЯрд╛ рд╕реЗрдЯ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реМрдВ:

CREATE TABLE tbl AS
SELECT
  (random() * 1000)::integer key_a
, (random() * 1000)::integer key_b
, (random() * 10000)::integer fld1
, (random() * 10000)::integer fld2
FROM
  generate_series(1, 10000);
CREATE INDEX ON tbl(key_a, key_b);

рддреНрдпреЛ рдмрд╛рд╣рд┐рд░ рдЬрд╛рдиреНрдЫ рдбрд╛рдЯрд╛ рдкрдвреНрди рд╕рдордпрдХреЛ рдПрдХ рдЪреМрдерд╛рдИ рднрдиреНрджрд╛ рдХрдо рд▓рд╛рдЧреНрдпреЛ рдХреНрд╡реЗрд░реА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:

PostgreSQL Antipatterns: CTE x CTE[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рдЯреБрдХреНрд░рд╛ рдЯреБрдХреНрд░рд╛ рдЯреБрдХреНрд░рд╛ рдкрд╛рд░реНрджреИ

рдЕрдиреБрд░реЛрдзрд▓рд╛рдИ рдирдЬрд┐рдХрдмрд╛рдЯ рд╣реЗрд░реМрдВ рд░ рдЕрдиреНрдпреЛрд▓рдорд╛ рдкрд░реМрдВ:

  1. рдпрджрд┐ рдХреБрдиреИ рдкреБрдирд░рд╛рд╡рд░реНрддреА CTE рд╣рд░реВ рдЫреИрдирдиреН рднрдиреЗ WITH RECURSIVE рдпрд╣рд╛рдБ рдХрд┐рди рдЫ?
  2. рдХрд┐рди рд╕рдореВрд╣ рдиреНрдпреВрдирддрдо/рдЕрдзрд┐рдХрддрдо рдорд╛рдирд╣рд░реВ рдЫреБрдЯреНрдЯреИ CTE рдорд╛ рд░рд╛рдЦрд┐рдиреНрдЫ рдпрджрд┐ рддрд┐рдиреАрд╣рд░реВ рдЬреЗ рднрдП рдкрдирд┐ рдореВрд▓ рдирдореВрдирд╛рдорд╛ рдмрд╛рдБрдзрд┐рдПрдХрд╛ рдЫрдиреН?
    +25% рд╕рдордп
  3. рдЕрдШрд┐рд▓реНрд▓реЛ CTE рджреЛрд╣реЛрд░реНрдпрд╛рдЙрдирдХреЛ рд▓рд╛рдЧрд┐ рдХрд┐рди рдЕрдиреНрддрдорд╛ рдмрд┐рдирд╛ рд╢рд░реНрдд 'SELECT * FROM' рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ?
    +14% рд╕рдордп

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

CTE рд╕реНрдХреНрдпрд╛рдирдХреЛ рдмрд╛рд░реЗрдорд╛ рдереЛрд░реИрдпрд╣рд╛рдБ рд╣рд╛рдореАрд▓реЗ рддреНрдпреЛ рдпрд╛рдж рдЧрд░реНрдиреБрдкрд░реНрдЫ CTE рд╕реНрдХреНрдпрд╛рди Seq рд╕реНрдХреНрдпрд╛рди рдЬрд╕реНрддреИ рдЫ - рддреНрдпреЛ рд╣реЛ, рдХреБрдиреИ рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдЫреИрди, рддрд░ рдХреЗрд╡рд▓ рдПрдХ рдкреВрд░реНрдг рдЦреЛрдЬ, рдЬрд╕рд▓рд╛рдИ рдЖрд╡рд╢реНрдпрдХ рдкрд░реНрджрдЫ 10K x 0.3ms = 3000ms cte_max рджреНрд╡рд╛рд░рд╛ рдЪрдХреНрд░рдХрд╛ рд▓рд╛рдЧрд┐ рд╡рд╛ 1K x 1.5ms = 1500ms cte_bind рджреНрд╡рд╛рд░рд╛ рд▓реБрдк рдЧрд░реНрджрд╛!
рд╡рд╛рд╕реНрддрд╡рдорд╛, рддрдкрд╛рдИрдВрд▓реЗ рдкрд░рд┐рдгрд╛рдордХреЛ рд░реВрдкрдорд╛ рдХреЗ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрди рдЪрд╛рд╣рдиреБрд╣реБрдиреНрдЫ? рд╣реЛ, рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛ рдпреЛ рдкреНрд░рд╢реНрди рд╣реЛ рдЬреБрди "рддреАрди-рдХрдерд╛" рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд╡рд┐рд╢реНрд▓реЗрд╖рдгрдХреЛ 5 рдФрдВ рдорд┐рдиреЗрдЯрдорд╛ рдХрддреИ рдЖрдЙрдБрдЫред

рд╣рд╛рдореА рдкреНрд░рддреНрдпреЗрдХ рдЕрджреНрд╡рд┐рддреАрдп рдХреБрдЮреНрдЬреА рдЬреЛрдбреАрдХреЛ рд▓рд╛рдЧрд┐ рдЖрдЙрдЯрдкреБрдЯ рдЧрд░реНрди рдЪрд╛рд╣рдиреНрдереНрдпреМрдВ key_a рджреНрд╡рд╛рд░рд╛ рд╕рдореВрд╣рдмрд╛рдЯ рдиреНрдпреВрдирддрдо/рдЕрдзрд┐рдХрддрдо.
рддреНрдпрд╕реИрд▓реЗ рдпрд╕рд▓рд╛рдИ рдпрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдкреНрд░рдпреЛрдЧ рдЧрд░реМрдВ рд╕рдЮреНрдЭреНрдпрд╛рд▓ рдХрд╛рд░реНрдпрд╣рд░реВ:

SELECT DISTINCT ON(key_a, key_b)
	key_a a
,	key_b b
,	max(fld1) OVER(w) bind_fld1
,	min(fld2) OVER(w) bind_fld2
FROM
	tbl
WINDOW
	w AS (PARTITION BY key_a);

PostgreSQL Antipatterns: CTE x CTE
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рджреБрдмреИ рд╡рд┐рдХрд▓реНрдкрд╣рд░реВрдорд╛ рдкрдвреНрдиреЗ рдбреЗрдЯрд╛рд▓реЗ рд▓рдЧрднрдЧ 4-5ms рд▓рд┐рдиреНрдЫ, рддреНрдпрд╕рдкрдЫрд┐ рд╣рд╛рдореНрд░реЛ рд╕рдмреИ рд╕рдордп рд▓рд╛рдн -32% - рдпреЛ рдпрд╕рдХреЛ рд╢реБрджреНрдз рд░реВрдк рдорд╛ рдЫ рдЖрдзрд╛рд░ CPU рдмрд╛рдЯ рд▓реЛрдб рд╣рдЯрд╛рдЗрдпреЛ, рдпрджрд┐ рдпрд╕реНрддреЛ рдЕрдиреБрд░реЛрдз рдЕрдХреНрд╕рд░ рдкрд░реНрдпрд╛рдкреНрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЧрд░рд┐рдиреНрдЫред

рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛, рддрдкрд╛рдИрдВрд▓реЗ рдЖрдзрд╛рд░рд▓рд╛рдИ "рд░рд╛рдЙрдиреНрдб рдПрдХ рдмреЛрдХреНрди, рд╕реНрдХреНрд╡рд╛рдпрд░ рдПрдХ рд░реЛрд▓" рдЧрд░реНрди рдмрд╛рдзреНрдп рдкрд╛рд░реНрдиреБ рд╣реБрдБрджреИрдиред

рд╕реНрд░реЛрдд: www.habr.com

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