PostgreSQL Antipatterns: рднрд╛рд░реА JOIN рдкрд░ рд╢рдмреНрджрдХреЛрд╢ рд╣рд┐рдЯ

рд╣рдо "рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рд╕рд░рд▓" PostgreSQL рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓реНрдкрдЬреНрдЮрд╛рдд рддрд░реАрдХреЛрдВ рдХреЗ рдЕрдзреНрдпрдпрди рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдкрд┐рдд рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВ:


рдРрд╕рд╛ рдордд рд╕реЛрдЪреЛ рдХрд┐ рдореБрдЭреЗ рдЬреЛрдЗрди рдкрд╕рдВрдж рдирд╣реАрдВ рд╣реИ ... :)

рд▓реЗрдХрд┐рди рдЕрдХреНрд╕рд░ рдЗрд╕рдХреЗ рдмрд┐рдирд╛, рдЕрдиреБрд░реЛрдз рдЙрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдлреА рдЕрдзрд┐рдХ рдЙрддреНрдкрд╛рджрдХ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЖрдЬ рд╣рдо рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рдХреА рдорджрдж рд╕реЗ рд╕рдВрд╕рд╛рдзрди-рдЧрд╣рди JOIN - рд╕реЗ рдкреВрд░реА рддрд░рд╣ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗред



PostgreSQL 12 рдХреЗ рд╕рд╛рде рд╢реБрд░реВ, рдиреАрдЪреЗ рд╡рд░реНрдгрд┐рдд рдХреБрдЫ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╕реАрдЯреАрдИ рдХреЗ рдЧреИрд░-рднреМрддрд┐рдХрдХрд░рдг рдХреЗ рдХрд╛рд░рдг рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдЦреЗрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ MATERIALIZED рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд╛рдкрд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдПрдХ рд╕реАрдорд┐рдд рд╢рдмреНрджрд╛рд╡рд▓реА рдкрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ "рддрдереНрдп"


рдЖрдЗрдП рдПрдХ рдмрд╣реБрдд рд╣реА рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЗрдВ - рдЖрдкрдХреЛ рдкреНрд░реЗрд╖рдХреЛрдВ рдХреЗ рд╕рд╛рде рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╕рдВрджреЗрд╢реЛрдВ рдпрд╛ рд╕рдХреНрд░рд┐рдп рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдирд╛ рд╣реЛрдЧрд╛:

 25.01 |  .. |    . 22.01 |  .. |    :   JOIN. 20.01 |  .. |   . 18.01 |  .. |    : JOIN    . 16.01 |  .. |   . 

рдЕрдореВрд░реНрдд рджреБрдирд┐рдпрд╛ рдореЗрдВ, рдХрд╛рд░реНрдп рд▓реЗрдЦрдХреЛрдВ рдХреЛ рд╕рдорд╛рди рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рд╕рдВрдЧрдарди рдХреЗ рд╕рднреА рдХрд░реНрдордЪрд╛рд░рд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдХрд╛рд░реНрдп, рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рдХрд╛рдлреА рд╣рдж рддрдХ рд╕реАрдорд┐рдд рд▓реЛрдЧреЛрдВ рд╕реЗ - "рдкрджрд╛рдиреБрдХреНрд░рдо" рд╕реЗ "рдкрджрд╛рдиреБрдХреНрд░рдо" рдпрд╛ рдкрдбрд╝реЛрд╕реА рд╡рд┐рднрд╛рдЧреЛрдВ рд╕реЗ "рд╕рд╣рдпреЛрдЧреА", рдбрд┐рдЬрд╛рдЗрдирд░ рд╡рд┐рдкрдгрди ...)ред

рдорд╛рди рд▓реЗрддреЗ рд╣реИрдВ рдХрд┐ 1000 рд▓реЛрдЧреЛрдВ рдХреЗ рд╣рдорд╛рд░реЗ рд╕рдВрдЧрдарди рдореЗрдВ, рдХреЗрд╡рд▓ 20 рд▓реЗрдЦрдХ (рдЖрдорддреМрд░ рдкрд░ рдЗрд╕рд╕реЗ рднреА рдХрдо) рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд▓рд╛рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ "рдкрд╛рд░рдВрдкрд░рд┐рдХ" рдЕрдиреБрд░реЛрдз рдХреЛ рддреЗрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рд╡рд┐рд╖рдп рдЬреНрдЮрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред

рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЬрдирд░реЗрдЯрд░
 --  CREATE TABLE person AS SELECT id , repeat(chr(ascii('a') + (id % 26)), (id % 32) + 1) "name" , '2000-01-01'::date - (random() * 1e4)::integer birth_date FROM generate_series(1, 1000) id; ALTER TABLE person ADD PRIMARY KEY(id); --     CREATE TABLE task AS WITH aid AS ( SELECT id , array_agg((random() * 999)::integer + 1) aids FROM generate_series(1, 1000) id , generate_series(1, 20) GROUP BY 1 ) SELECT * FROM ( SELECT id , '2020-01-01'::date - (random() * 1e3)::integer task_date , (random() * 999)::integer + 1 owner_id FROM generate_series(1, 100000) id ) T , LATERAL( SELECT aids[(random() * (array_length(aids, 1) - 1))::integer + 1] author_id FROM aid WHERE id = T.owner_id LIMIT 1 ) a; ALTER TABLE task ADD PRIMARY KEY(id); CREATE INDEX ON task(owner_id, task_date); CREATE INDEX ON task(author_id); 

рд╣рдо рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд▓рд╛рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо 100 рдХрд╛рд░реНрдп рджрд┐рдЦрд╛рддреЗ рд╣реИрдВ:

 SELECT task.* , person.name FROM task LEFT JOIN person ON person.id = task.author_id WHERE owner_id = 777 ORDER BY task_date DESC LIMIT 100; 


[рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдкрд░ рджреЗрдЦреЗрдВ редensor.ru]

рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдкреВрд░реЗ рд╕рдордп рдХреЗ 1/3 рдФрд░ рдбреЗрдЯрд╛ рдкреГрд╖реНрдареЛрдВ рдХреА 3/4 рд░реАрдбрд┐рдВрдЧ рдХреЗрд╡рд▓ 100 рдмрд╛рд░ - рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рд▓реЗрдЦрдХ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдИ рдЧрдИ рдереАрдВред рд▓реЗрдХрд┐рди рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЗрд╕ рд╕реМ рдореЗрдВ рд╕реЗ рдХреЗрд╡рд▓ 20 рдЕрд▓рдЧ - рдЕрд▓рдЧ рд╣реИрдВ - рдХреНрдпрд╛ рдЗрд╕ рдЬреНрдЮрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ?

hstore рд╢рдмреНрджрдХреЛрд╢


рд╣рдо рдХреБрдВрдЬреА-рдореВрд▓реНрдп "рд╢рдмреНрджрдХреЛрд╢" рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП hstore рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ :

 CREATE EXTENSION hstore 

рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд▓реЗрдЦрдХ рдХреА рдЖрдИрдбреА рдФрд░ рдЙрд╕рдХреЗ рдирд╛рдо рдХреЛ рдбрд┐рдХреНрд╢рдирд░реА рдореЗрдВ рд░рдЦрдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рддрд╛рдХрд┐ рдмрд╛рдж рдореЗрдВ рд╣рдо рдЗрд╕ рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдирд┐рдХрд╛рд▓ рд╕рдХреЗрдВ:

 --    WITH T AS ( SELECT * FROM task WHERE owner_id = 777 ORDER BY task_date DESC LIMIT 100 ) --      , dict AS ( SELECT hstore( -- hstore(keys::text[], values::text[]) array_agg(id)::text[] , array_agg(name)::text[] ) FROM person WHERE id = ANY(ARRAY( SELECT DISTINCT author_id FROM T )) ) --     SELECT * , (TABLE dict) -> author_id::text -- hstore -> key FROM T; 


[рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдкрд░ рджреЗрдЦреЗрдВ редensor.ru]

рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ 2 рдЧреБрдирд╛ рдХрдо рд╕рдордп рд▓рдЧрд╛ рдФрд░ 7 рдмрд╛рд░ рдХрдо рдбреЗрдЯрд╛ рдкрдврд╝рд╛ рдЧрдпрд╛ ! "рдзреЛрдЦреЗ" рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрди рдкрд░рд┐рдгрд╛рдореЛрдВ рдиреЗ рднреА рд╣рдореЗрдВ = ANY(ARRAY(...)) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдПрдХрд▓ рдкрд╛рд╕ рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рд░рд┐рдХреЙрд░реНрдб рдХреЗ рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдирд┐рд╖реНрдХрд░реНрд╖рдг рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХреАред

рддрд╛рд▓рд┐рдХрд╛ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпрд╛рдБ: рдХреНрд░рдорд╛рдВрдХрди рдФрд░ рдбреАрд░рд╛рдЗрдЬрд╝реЗрд╢рди


рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдЕрдЧрд░ рд╣рдореЗрдВ рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ рдПрдХ рдкрд╛рда рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдкреВрд░реЗ рд░рд┐рдХреЙрд░реНрдб рдХреЛ рд╕рд╣реЗрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ? рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, PostgreSQL рдХреА рдПрдХ рдПрдХрд▓ рдорд╛рди рдХреЗ рд░реВрдк рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧреА:

 ... , dict AS ( SELECT hstore( array_agg(id)::text[] , array_agg(p)::text[] --  #1 ) FROM person p WHERE ... ) SELECT * , (((TABLE dict) -> author_id::text)::person).* --  #2 FROM T; 

рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдпрд╣рд╛рдВ рдХреНрдпрд╛ рд╣реБрдЖ:

  1. рд╣рдордиреЗ рд╡реНрдпрдХреНрддрд┐ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рдкреВрд░реНрдг рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдирд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдкреА рд▓рд┐рдпрд╛ рдФрд░ рдЙрдирд╕реЗ рдПрдХ рд╕рд░рдгреА рдЗрдХрдЯреНрдареА рдХреАред
  2. рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпреЛрдВ рдХреА рдпрд╣ рд╕рд░рдгреА рдкрд╛рда рд╕реНрдЯреНрд░рд┐рдВрдЧ (рд╡реНрдпрдХреНрддрд┐ [] :: рдкрд╛рда []] рдХреА рдПрдХ рд╕рд░рдгреА рдореЗрдВ рдЗрд╕реЗ рдореВрд▓реНрдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ hstore рд╢рдмреНрджрдХреЛрд╢ рдореЗрдВ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдлрд┐рд░ рд╕реЗ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
  3. рд▓рд┐рдВрдХ рдХрд┐рдП рдЧрдП рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдкрд░, рд╣рдордиреЗ рдЗрд╕реЗ рдЯреЗрдХреНрд╕реНрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдХреБрдВрдЬреА рджреНрд╡рд╛рд░рд╛ рд╢рдмреНрджрдХреЛрд╢ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓рд╛ ред
  4. рд╣рдореЗрдВ рдкрд╛рда рдХреЛ рд╡реНрдпрдХреНрддрд┐ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рдкреНрд░рдХрд╛рд░ (рдкреНрд░рддреНрдпреЗрдХ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП, рдЙрд╕реА рдирд╛рдо рдХрд╛ рдкреНрд░рдХрд╛рд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ) рдХреЗ рдореВрд▓реНрдп рдореЗрдВ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ ред
  5. " (...).* рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЙрд▓рдо рдореЗрдВ рдПрдХ рдЯрд╛рдЗрдк рдХрд┐рдП рдЧрдП рд░рд┐рдХреЙрд░реНрдб рдХреЛ" рдирд┐рдпреЛрдЬрд┐рдд " (...).* ред

json рд╢рдмреНрджрдХреЛрд╢


рд▓реЗрдХрд┐рди рдЗрд╕ рддрд░рд╣ рдХреА рдПрдХ рдЪрд╛рд▓, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдордиреЗ рдКрдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рд╣реИ, "рдЕрдирдлрд╝рд┐рдЯрд┐рдВрдЧ" рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрдмрдВрдзрд┐рдд рддрд╛рд▓рд┐рдХрд╛ рдкреНрд░рдХрд╛рд░ рдирд╣реАрдВ рд╣реЛрдиреЗ рдкрд░ рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдмрд┐рд▓реНрдХреБрд▓ рд╡реИрд╕реА рд╣реА рд╕реНрдерд┐рддрд┐ рдкреИрджрд╛ рд╣реЛрдЧреА, рдФрд░ рдпрджрд┐ рдХреНрд░рдорд╛рдВрдХрди рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рд╣рдо рд╕реАрдЯреАрдИ рдкрдВрдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ , рди рдХрд┐ "рд╡рд╛рд╕реНрддрд╡рд┐рдХ" рддрд╛рд▓рд┐рдХрд╛ ред

рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, json рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдВрдЧреЗ:

 ... , p AS ( --   CTE SELECT * FROM person WHERE ... ) , dict AS ( SELECT json_object( --    json array_agg(id)::text[] , array_agg(row_to_json(p))::text[] --   json    ) FROM p ) SELECT * FROM T , LATERAL( SELECT * FROM json_to_record( ((TABLE dict) ->> author_id::text)::json --     json ) AS j(name text, birth_date date) --     ) j; 

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

рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдПрдХ рдмрд╛рд░ рд╢рдмреНрджрдХреЛрд╢ рдХреА рдкрд╣реБрдВрдЪ рд╣реИ, рд▓реЗрдХрд┐рди json- [de] рдХреНрд░рдорд╛рдВрдХрди рдХреА рд▓рд╛рдЧрдд рдХрд╛рдлреА рдЕрдзрд┐рдХ рд╣реИ , рдЗрд╕рд▓рд┐рдП рдЗрд╕ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХрд░рдирд╛ рдЙрдЪрд┐рдд рд╣реИ рдЬрдм "рдИрдорд╛рдирджрд╛рд░" рд╕реАрдЯреАрдИ рд╕реНрдХреИрди рдЦреБрдж рдХреЛ рдмрджрддрд░ рджрд┐рдЦрд╛рддрд╛ рд╣реИред

рдкрд░реАрдХреНрд╖рдг рдкреНрд░рджрд░реНрд╢рди


рдЗрд╕рд▓рд┐рдП, рд╣рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдбрд┐рдХреНрд╢рдирд░реА рдореЗрдВ рдХреНрд░рдордмрджреНрдз рдХрд░рдиреЗ рдХреЗ рджреЛ рддрд░реАрдХреЗ рдорд┐рд▓реЗ - hstore / json_object ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреБрдВрдЬрд┐рдпреЛрдВ рдФрд░ рдореВрд▓реНрдпреЛрдВ рдХреА рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рджреЛ рддрд░рд╣ рд╕реЗ рднреА рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдкрд╛рда рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рдпрд╛ рдмрд╛рд╣реНрдп рд░реВрдкрд╛рдВрддрд░рдг рдХреЗ рд╕рд╛рде: array_agg (i :: text) / array_agg (i) :: рдкрд╛рда [] ред

рдЪрд▓реЛ рд╡рд┐рд╢реБрджреНрдз рд░реВрдк рд╕реЗ рд╕рд┐рдВрдереЗрдЯрд┐рдХ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдХреНрд░рдорд╛рдВрдХрди рдХреА рдкреНрд░рднрд╛рд╡рд╢реАрд▓рддрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ - рд╣рдо рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреА рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдХреНрд░рдордмрджреНрдз рдХрд░рддреЗ рд╣реИрдВ :

 WITH dict AS ( SELECT hstore( array_agg(i::text) , array_agg(i::text) ) FROM generate_series(1, ...) i ) TABLE dict; 

рдореВрд▓реНрдпрд╛рдВрдХрди рд╕реНрдХреНрд░рд┐рдкреНрдЯ: рдХреНрд░рдорд╛рдВрдХрди
 WITH T AS ( SELECT * , ( SELECT regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (\d+\.\d+) ms$', '\1')::real et FROM ( SELECT array_agg(el) ea FROM dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$ explain analyze WITH dict AS ( SELECT hstore( array_agg(i::text) , array_agg(i::text) ) FROM generate_series(1, $$ || (1 << v) || $$) i ) TABLE dict $$) T(el text) ) T ) et FROM generate_series(0, 19) v , LATERAL generate_series(1, 7) i ORDER BY 1, 2 ) SELECT v , avg(et)::numeric(32,3) FROM T GROUP BY 1 ORDER BY 1; 



PostgreSQL 11 рдкрд░, 2 ^ 12 рдХреБрдВрдЬреА рдХреЗ рд╢рдмреНрджрдХреЛрд╢ рдЖрдХрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдЬреЛрд╕рди рдореЗрдВ рдХреНрд░рдордмрджреНрдз рд╣реЛрдиреЗ рдореЗрдВ рдХрдо рд╕рдордп рд▓рдЧрддрд╛ рд╣реИ ред Json_object рдХрд╛ рд╕рдВрдпреЛрдЬрди рдФрд░ array_agg(i::text) рдХрд╛ "рдЖрдВрддрд░рд┐рдХ" рдкреНрд░рдХрд╛рд░ рд░реВрдкрд╛рдВрддрд░рдг рд╕рдмрд╕реЗ рдХреБрд╢рд▓ рд╣реИред

рдЕрдм рдЪрд▓реЛ рдкреНрд░рддреНрдпреЗрдХ рдХреБрдВрдЬреА рдХреЗ рдореВрд▓реНрдп рдХреЛ 8 рдмрд╛рд░ рдкрдврд╝рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ - рдХреНрдпреЛрдВрдХрд┐ рдпрджрд┐ рдЖрдк рд╢рдмреНрджрдХреЛрд╢ рддрдХ рдирд╣реАрдВ рдкрд╣реБрдВрдЪрддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ?

рдореВрд▓реНрдпрд╛рдВрдХрди рд╕реНрдХреНрд░рд┐рдкреНрдЯ: рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд╕реЗ рдкрдврд╝рдирд╛
 WITH T AS ( SELECT * , ( SELECT regexp_replace(ea[array_length(ea, 1)], '^Execution Time: (\d+\.\d+) ms$', '\1')::real et FROM ( SELECT array_agg(el) ea FROM dblink('port= ' || current_setting('port') || ' dbname=' || current_database(), $$ explain analyze WITH dict AS ( SELECT json_object( array_agg(i::text) , array_agg(i::text) ) FROM generate_series(1, $$ || (1 << v) || $$) i ) SELECT (TABLE dict) -> (i % ($$ || (1 << v) || $$) + 1)::text FROM generate_series(1, $$ || (1 << (v + 3)) || $$) i $$) T(el text) ) T ) et FROM generate_series(0, 19) v , LATERAL generate_series(1, 7) i ORDER BY 1, 2 ) SELECT v , avg(et)::numeric(32,3) FROM T GROUP BY 1 ORDER BY 1; 



рдФрд░ ... рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд▓рдЧрднрдЧ 2 ^ 6 рдХреАрдЬрд╝ рдкрд░, json-рдбрд┐рдХреНрд╢рдирд░реА рд╕реЗ рдкрдврд╝рдирд╛ рдХрдИ рдмрд╛рд░ hstore рд╕реЗ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреЛрдирд╛ рд╢реБрд░реВ рдХрд░ рджреЗрддрд╛ рд╣реИ , jsonb рдХреЗ рд▓рд┐рдП рд╡рд╣реА рдЪреАрдЬрд╝ 2 ^ 9 рдкрд░ рд╣реЛрддреА рд╣реИред
рдЕрдВрддрд┐рдо рдирд┐рд╖реНрдХрд░реНрд╖:

  • рдпрджрд┐ рдЖрдкрдХреЛ рдмрд╛рд░-рдмрд╛рд░ рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд╕рд╛рде рдПрдХ JOIN рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - "рдЯреЗрдмрд▓ рдорд┐рд▓рд╛рди" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ
  • рдпрджрд┐ рдЖрдкрдХрд╛ рд╢рдмреНрджрдХреЛрд╢ рдЕрдкреЗрдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЫреЛрдЯрд╛ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рдкрдврд╝реЗрдВрдЧреЗ - рддреЛ рдЖрдк json [b] рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ
  • рдЕрдиреНрдп рд╕рднреА рдорд╛рдорд▓реЛрдВ рдореЗрдВ, hstore + array_agg (i :: text) рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рд╣реЛрдЧрд╛

Source: https://habr.com/ru/post/hi485398/


All Articles