рдорд╛рдЭреНрдпрд╛ рдХрд╛рд░реНрдпрдкрджреНрдзрддреАрдореБрд│реЗ, рдЬреЗрд╡реНрд╣рд╛ рд╡рд┐рдХрд╛рд╕рдХ рд╡рд┐рдирдВрддреА рд▓рд┐рд╣рд┐рддреЛ рдЖрдгрд┐ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЛ рддреЗрд╡реНрд╣рд╛ рдорд▓рд╛ рдЕрд╢рд╛ рдкрд░рд┐рд╕реНрдерд┐рддреАрдВрдЪрд╛ рд╕рд╛рдордирд╛ рдХрд░рд╛рд╡рд╛ рд▓рд╛рдЧрддреЛ тАЬрдмреЗрд╕ рд╣реБрд╢рд╛рд░ рдЖрд╣реЗ, рддреЛ рд╕реНрд╡рддрдГ рд╕рд░реНрд╡рдХрд╛рд╣реА рд╣рд╛рддрд╛рд│реВ рд╢рдХрддреЛ!┬л
рдХрд╛рд╣реА рдкреНрд░рдХрд░рдгрд╛рдВрдордзреНрдпреЗ (рдЕрдВрд╢рддрдГ рдбреЗрдЯрд╛рдмреЗрд╕рдЪреНрдпрд╛ рдХреНрд╖рдорддреЗрдЪреНрдпрд╛ рдЕрдЬреНрдЮрд╛рдирд╛рдореБрд│реЗ, рдЕрдВрд╢рддрдГ рдЕрдХрд╛рд▓реА рдСрдкреНрдЯрд┐рдорд╛рдпрдЭреЗрд╢рдирдореБрд│реЗ), рд╣рд╛ рджреГрд╖реНрдЯреАрдХреЛрди "рдлреНрд░рдБрдХреЗрдиреНрд╕реНрдЯрд╛рдИрди" рджрд┐рд╕рдгреНрдпрд╛рд╕ рдХрд╛рд░рдгреАрднреВрдд рдард░рддреЛ.
рдкреНрд░рдердо, рдореА рдЕрд╢рд╛ рд╡рд┐рдирдВрддреАрдЪреЗ рдЙрджрд╛рд╣рд░рдг рджреЗрдИрди:
-- ╨┤╨╗╤П ╨║╨░╨╢╨┤╨╛╨╣ ╨║╨╗╤О╤З╨╡╨▓╨╛╨╣ ╨┐╨░╤А╤Л ╨╜╨░╤Е╨╛╨┤╨╕╨╝ ╨░╤Б╤Б╨╛╤Ж╨╕╨╕╤А╨╛╨▓╨░╨╜╨╜╤Л╨╡ ╨╖╨╜╨░╤З╨╡╨╜╨╕╤П ╨┐╨╛╨╗╨╡╨╣
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);
рддреЗ рдмрд╛рд╣реЗрд░ рд╡рд│рддреЗ рдбреЗрдЯрд╛ рд╡рд╛рдЪрдгреНрдпрд╛рдд рдПрдХ рдЪрддреБрд░реНрдерд╛рдВрд╢рдкреЗрдХреНрд╖рд╛ рдХрдореА рд╡реЗрд│ рд▓рд╛рдЧрд▓рд╛ рдХреНрд╡реЗрд░реА рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА:
рддреБрдХрдбреНрдпрд╛ рддреБрдХрдбреНрдпрд╛рдиреЗ рд╡реЗрдЧрд│реЗ рдХрд░рдгреЗ
рдЪрд▓рд╛ рд╡рд┐рдирдВрддреАрдХрдбреЗ рдЬрд╡рд│реВрди рдкрд╛рд╣реВ рдЖрдгрд┐ рдЧреЛрдВрдзрд│реВрди рдЬрд╛рдК:
- рдЬрд░ рд░рд┐рдХрд░реНрд╕рд┐рд╡ CTE рдирд╕рддреАрд▓ рддрд░ WITH RECURSIVE рдЗрдереЗ рдХрд╛ рдЖрд╣реЗ?
- рд╡реЗрдЧрд│реНрдпрд╛ CTE рдордзреАрд▓ рдХрд┐рдорд╛рди/рдЕрдзрд┐рдХрддрдо рдореВрд▓реНрдпреЗ рдореВрд│ рдирдореБрдиреНрдпрд╛рд╢реА рдЬреЛрдбрд▓реА рдЧреЗрд▓реНрдпрд╛рд╕ рддреА рдХрд╛ рдЧрдЯ рдХрд░рд╛рдпрдЪреА?
+25% рд╡реЗрд│ - рдорд╛рдЧреАрд▓ CTE рдЪреА рдкреБрдирд░рд╛рд╡реГрддреНрддреА рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рд╢реЗрд╡рдЯреА рдмрд┐рдирд╢рд░реНрдд 'SELECT * FROM' рдХрд╛ рд╡рд╛рдкрд░рд╛рд╡реЗ?
+14% рд╡реЗрд│
рдпрд╛ рдкреНрд░рдХрд░рдгрд╛рдд, рдЖрдореНрд╣реА рдЦреВрдк рднрд╛рдЧреНрдпрд╡рд╛рди рдЖрд╣реЛрдд рдХреА рдХрдиреЗрдХреНрд╢рдирд╕рд╛рдареА рд╣реЕрд╢ рдЬреЙрдИрди рдирд┐рд╡рдбрд▓реЗ рдЧреЗрд▓реЗ рд╣реЛрддреЗ, рдиреЗрд╕реНрдЯреЗрдб рд▓реВрдк рдирд╛рд╣реА, рдХрд╛рд░рдг рддреЗрд╡реНрд╣рд╛ рдЖрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд рдПрдХ CTE рд╕реНрдХреЕрди рдкрд╛рд╕ рдорд┐рд│рд╛рд▓рд╛ рдирд╕рддрд╛ рддрд░ 10K!
CTE рд╕реНрдХреЕрди рдмрджреНрджрд▓ рдереЛрдбреЗрд╕реЗрдпреЗрдереЗ рдЖрдкрдг рддреЗ рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рд▓реЗ рдкрд╛рд╣рд┐рдЬреЗ рд╕реАрдЯреАрдИ рд╕реНрдХреЕрди рд╣реЗ рд╕реЗрдХ рд╕реНрдХреЕрдирд╕рд╛рд░рдЦреЗрдЪ рдЖрд╣реЗ - рдореНрд╣рдгрдЬреЗ, рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдирд╛рд╣реА, рдкрд░рдВрддреБ рдХреЗрд╡рд│ рдПрдХ рд╕рдВрдкреВрд░реНрдг рд╢реЛрдз, рдЬреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЕрд╕реЗрд▓ 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);
рджреЛрдиреНрд╣реА рдкрд░реНрдпрд╛рдпрд╛рдВрдордзреНтАНрдпреЗ рдбреЗрдЯрд╛ рд╡рд╛рдЪрдгреНтАНрдпрд╛рд╕рд╛рдареА рдЕрдВрджрд╛рдЬреЗ 4-5ms рдЗрддрдХрд╛рдЪ рд╡реЗрд│ рд▓рд╛рдЧрддреЛ, рдордЧ рдЖрдордЪрд╛ рд╕рд░реНрд╡ рд╡реЗрд│ рд╡рд╛рдврддреЛ -32% - рд╣реЗ рддреНрдпрд╛рдЪреНрдпрд╛ рд╢реБрджреНрдз рд╕реНрд╡рд░реВрдкрд╛рдд рдЖрд╣реЗ рдмреЗрд╕ CPU рд╡рд░реВрди рд▓реЛрдб рдХрд╛рдврд▓реЗ, рдЬрд░ рдЕрд╢реА рд╡рд┐рдирдВрддреА рдкреБрд░реЗрд╢реА рдЕрдВрдорд▓рд╛рдд рдЖрдгрд▓реА рдЬрд╛рддреЗ.
рд╕рд░реНрд╡рд╕рд╛рдзрд╛рд░рдгрдкрдгреЗ, рддреБрдореНрд╣реА рдмреЗрд╕рд▓рд╛ "рдЧреЛрд▓рд╛рдХрд╛рд░ рдШреЗрдКрди рдЬрд╛, рдЪреМрдХреЛрдиреА рд░реЛрд▓ рдХрд░рд╛" рдЕрд╢реА рд╕рдХреНрддреА рдХрд░реВ рдирдпреЗ.
рд╕реНрддреНрд░реЛрдд: www.habr.com