PostgreSQL Antipatterns: рдПрдХ рдЯреНрд░рд┐рдЧрд░ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рддреЗ рд╣реБрдП рдбреЗрдЯрд╛ рдмрджрд▓реЗрдВ

рдЬрд▓реНрджреА рдпрд╛ рдмрд╛рдж рдореЗрдВ, рдХрдИ рд▓реЛрдЧреЛрдВ рдХреЛ рдЯреЗрдмрд▓ рд░рд┐рдХреЙрд░реНрдб рдореЗрдВ рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдХреБрдЫ рдареАрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред рдореЗрд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣реИ рдореБрдЭреЗ рдмрддрд╛рдУ рдХрд┐ рдЗрд╕реЗ рдмреЗрд╣рддрд░ рдХреИрд╕реЗ рдХрд░реЗрдВ, рдФрд░ рдХреИрд╕реЗ - рдпрд╣ рдмреЗрд╣рддрд░ рдирд╣реАрдВ рд╣реИред рдЖрдЬ рдореИрдВ рдорд╛рд╕ рдЕрдкрдбреЗрдЯ рдХреЗ рджреВрд╕рд░реЗ рдкрд╣рд▓реВ рдХреА рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ - рдЯреНрд░рд┐рдЧрд░реНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ.

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

рдЪрд▓реЛ рдмрд╕ рдЯреНрд░рд┐рдЧрд░реНрд╕ рдХреЛ рдЕрдХреНрд╖рдо рдХрд░реЗрдВ!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- ╤В╤Г╤В ╨┤╨╛╨╗╨│╨╛-╨┤╨╛╨╗╨│╨╛
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

рджрд░рдЕрд╕рд▓, рдмрд╕ рдЗрддрдирд╛ рд╣реА- рд╕рдм рдХреБрдЫ рд▓рдЯрдХ рд░рд╣рд╛ рд╣реИ.

рдХреНрдпреЛрдВрдХрд┐ ALTER TABLE рд▓рдЧрд╛рддрд╛ рдПрдХреНрд╕реЗрд╕ рдПрдХреНрд╕рдХреНрд▓реВрд╕рд┐рд╡- рдПрдХ рддрд╛рд▓рд╛ рдЬрд┐рд╕рдХреЗ рдиреАрдЪреЗ рдХреЛрдИ рднреА рд╕рдорд╛рдирд╛рдВрддрд░ рдирд╣реАрдВ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдХрд┐ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рднреА SELECT, рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреБрдЫ рднреА рдкрдврд╝рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдпрд╣реА рд╣реИ, рдЬрдм рддрдХ рдпрд╣ рд▓реЗрди-рджреЗрди рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддрд╛, рддрдм рддрдХ рд╣рд░ рдХреЛрдИ рдЬреЛ "рд╕рд┐рд░реНрдл рдкрдврд╝рдирд╛" рдЪрд╛рд╣рддрд╛ рд╣реИ, рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдЧрд╛ред рдФрд░ рд╣рдореЗрдВ рд╡рд╣ рдпрд╛рдж рд╣реИ UPDATE рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд▓рдВрдмрд╛...

рдЪрд▓реЛ рдЬрд▓реНрджреА рд╕реЗ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рджреЗрдВ, рдлрд┐рд░ рдЬрд▓реНрджреА рд╕реЗ рдЪрд╛рд▓реВ рдХрд░реЗрдВ!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;

UPDATE ...;

BEGIN;
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

рдпрд╣рд╛рдВ рд╕реНрдерд┐рддрд┐ рдкрд╣рд▓реЗ рд╕реЗ рдмреЗрд╣рддрд░ рд╣реИ, рд╡реЗрдЯрд┐рдВрдЧ рдЯрд╛рдЗрдо рдХрд╛рдлреА рдХрдо рд╣реИред рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рджреЛ рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реА рд╕рд╛рд░реА рд╕реБрдВрджрд░рддрд╛ рдмрд┐рдЧрд╛рдбрд╝ рджреЗрддреА рд╣реИрдВ:

  • ALTER TABLE рдореЗрдЬ рдкрд░ рдЕрдиреНрдп рд╕рднреА рдкрд░рд┐рдЪрд╛рд▓рдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдпрдВ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд▓рдВрдмреЗ рднреА рд╢рд╛рдорд┐рд▓ рд╣реИрдВ SELECT
  • рдЬрдмрдХрд┐ рдЯреНрд░рд┐рдЧрд░ рдмрдВрдж рд╣реИ, рдХрд┐рд╕реА рднреА рдмрджрд▓рд╛рд╡ рд╕реЗ "рдЙрдбрд╝рд╛рди рднрд░реЗрдВ" рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ, рд╣рдорд╛рд░рд╛ рднреА рдирд╣реАрдВред рдФрд░ рдпрд╣ рд╕рдореБрдЪреНрдЪрдп рдореЗрдВ рдирд╣реАрдВ рдЖрдПрдЧрд╛, рд╣рд╛рд▓рд╛рдБрдХрд┐ рдЗрд╕реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдореБрд╢реНрдХрд┐рд▓!

рд╕рддреНрд░ рдЪрд░ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдирд╛

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

рд╕рддреНрд░_рдкреНрд░рддрд┐рдХреГрддрд┐_рднреВрдорд┐рдХрд╛

рд╣рдо рдкрдврд╝рддреЗ рд╣реИрдВ рдирд┐рдпрдорд╛рд╡рд▓реА:

рдЯреНрд░рд┐рдЧрд░ рддрдВрддреНрд░ рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЪрд░ рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛрддрд╛ рд╣реИ рд╕рддреНрд░_рдкреНрд░рддрд┐рдХреГрддрд┐_рднреВрдорд┐рдХрд╛. рдЕрддрд┐рд░рд┐рдХреНрдд рдирд┐рд░реНрджреЗрд╢реЛрдВ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ) рдХреЗ рдмрд┐рдирд╛ рд╕рдХреНрд╖рдо, рдкреНрд░рддрд┐рдХреГрддрд┐ рднреВрдорд┐рдХрд╛ "рдореВрд▓" (рдбрд┐рдлрд╝реЙрд▓реНрдЯ) рдпрд╛ "рд╕реНрдерд╛рдиреАрдп" рд╣реЛрдиреЗ рдкрд░ рдЯреНрд░рд┐рдЧрд░ рд╕рдХреНрд░рд┐рдп рд╣реЛ рдЬрд╛рдПрдВрдЧреЗред рдЯреНрд░рд┐рдЧрд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдХреЗ рд╕рдХреНрд╖рдо рдХрд┐рдпрд╛ рдЧрдпрд╛ ENABLE REPLICA, рддрднреА рдХрд╛рдо рдХрд░реЗрдЧрд╛ рд╡рд░реНрддрдорд╛рди рд╕рддреНрд░ рдореЛрдб - "рдкреНрд░рддрд┐рдХреГрддрд┐", рдФрд░ рдЯреНрд░рд┐рдЧрд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдХреЗ рд╕рдХреНрд╖рдо ENABLE ALWAYS, рд╡рд░реНрддрдорд╛рди рдкреНрд░рддрд┐рдХреГрддрд┐ рдореЛрдб рдкрд░ рдзреНрдпрд╛рди рджрд┐рдП рдмрд┐рдирд╛ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред

рдореИрдВ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЗрд╕ рдмрд╛рдд рдкрд░ рдЬреЛрд░ рджреВрдВрдЧрд╛ рдХрд┐ рд╕реЗрдЯрд┐рдВрдЧ рд╕рднреА-рд╕рднреА рдкрд░ рдПрдХ рд╕рд╛рде рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рдЬреИрд╕реЗ ALTER TABLE, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рд╣рдорд╛рд░реЗ рдЕрд▓рдЧ рд╡рд┐рд╢реЗрд╖ рдХрдиреЗрдХреНрд╢рди рдХреЗ рд▓рд┐рдПред рдХреБрд▓ рдорд┐рд▓рд╛рдХрд░, рддрд╛рдХрд┐ рдХреЛрдИ рднреА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЯреНрд░рд┐рдЧрд░ рдХрд╛рдо рди рдХрд░реЗ:

SET session_replication_role = replica; -- ╨▓╤Л╨║╨╗╤О╤З╨╕╨╗╨╕ ╤В╤А╨╕╨│╨│╨╡╤А╤Л
UPDATE ...;
SET session_replication_role = DEFAULT; -- ╨▓╨╡╤А╨╜╤Г╨╗╨╕ ╨▓ ╨╕╤Б╤Е╨╛╨┤╨╜╨╛╨╡ ╤Б╨╛╤Б╤В╨╛╤П╨╜╨╕╨╡

рдЯреНрд░рд┐рдЧрд░ рдХреЗ рдЕрдВрджрд░ рдХреА рд╕реНрдерд┐рддрд┐

рд▓реЗрдХрд┐рди рдЙрдкрд░реЛрдХреНрдд рд╡рд┐рдХрд▓реНрдк рдПрдХ рд╕рд╛рде рд╕рднреА рдЯреНрд░рд┐рдЧрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ (рдпрд╛ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ "рд╡реИрдХрд▓реНрдкрд┐рдХ" рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдЕрдХреНрд╖рдо рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ)ред рдФрд░ рдЕрдЧрд░ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЯреНрд░рд┐рдЧрд░ "рдмрдВрдж рдХрд░реЗрдВ"?

рдЗрд╕рд╕реЗ рд╣рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреА "рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛" рд╕рддреНрд░ рдЪрд░:

рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдкреИрд░рд╛рдореАрдЯрд░ рдирд╛рдо рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд▓рд┐рдЦреЗ рдЧрдП рд╣реИрдВ: рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдирд╛рдо рдХреЗ рдмрд╛рдж рдбреЙрдЯ рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рдкреИрд░рд╛рдореАрдЯрд░ рдирд╛рдо, SQL рдореЗрдВ рдкреВрд░реНрдг рдСрдмреНрдЬреЗрдХреНрдЯ рдирд╛рдореЛрдВ рдХреЗ рд╕рдорд╛рдиред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП: plpgsql.variable_conflictред
рдХреНрдпреЛрдВрдХрд┐ рдЖрдЙрдЯ-рдСрдлрд╝-рд╕рд┐рд╕реНрдЯрдо рд╡рд┐рдХрд▓реНрдк рдЙрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЙрдкрдпреБрдХреНрдд рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдореЙрдбреНрдпреВрд▓ рдХреЛ рд▓реЛрдб рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, PostgreSQL рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ рджреЛ рдШрдЯрдХреЛрдВ рд╡рд╛рд▓реЗ рдХрд┐рд╕реА рднреА рдирд╛рдо рдХреЗ рдорд╛рди.

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдЯреНрд░рд┐рдЧрд░ рдХреЛ рдЕрдВрддрд┐рдо рд░реВрдк рджреЗрддреЗ рд╣реИрдВ, рдХреБрдЫ рдЗрд╕ рддрд░рд╣:

BEGIN
    -- ╨┐╤А╨╛╤Ж╨╡╤Б╤Б╤Г ╨║╨╛╨╜╨▓╨╡╤А╤В╨░╤Ж╨╕╨╕ ╨╝╨╛╨╢╨╜╨╛ ╨┤╨╡╨╗╨░╤В╤М ╨▓╤Б╨╡
    IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
        IF TG_OP IN ('INSERT', 'UPDATE') THEN
            RETURN NEW;
        ELSE
            RETURN OLD;
        END IF;
    END IF;
...

рд╡реИрд╕реЗ, рдпрд╣ "рд▓рд╛рдн рдХреЗ рд▓рд┐рдП" рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдмрд┐рдирд╛ рдЕрд╡рд░реБрджреНрдз рдХрд┐рдП CREATE OR REPLACE рдЯреНрд░рд┐рдЧрд░ рд╕рдорд╛рд░реЛрд╣ рдХреЗ рд▓рд┐рдПред рдФрд░ рдлрд┐рд░ рд╡рд┐рд╢реЗрд╖ рд╕рдВрдмрдВрдз рдореЗрдВ рд╣рдо "рд╣рдорд╛рд░реЗ" рдЪрд░ рдХреЛ рдХреЙрдХ рдХрд░рддреЗ рд╣реИрдВ:


SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- ╨▓╨╡╤А╨╜╤Г╨╗╨╕ ╨▓ ╨╕╤Б╤Е╨╛╨┤╨╜╨╛╨╡ ╤Б╨╛╤Б╤В╨╛╤П╨╜╨╕╨╡

рдХреНрдпрд╛ рдЖрдк рдЕрдиреНрдп рддрд░реАрдХреЗ рдЬрд╛рдирддреЗ рд╣реИрдВ? рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рд╕рд╛рдЭрд╛ рдХрд░реЗрдВред

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ