рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐

рдорд╣реАрдиреЗ рдкрд╣рд▓реЗ рд╣рдордиреЗ рдШреЛрд╖рдгрд╛ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ - рдЬрдирддрд╛ рдХреНрд╡реЗрд░реА рдпреЛрдЬрдирд╛рдУрдВ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдФрд░ рд╡рд┐рдЬрд╝реБрдЕрд▓рд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрд╡рд╛ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдПрд╕рдХреНрдпреВрдПрд▓ рдХреЗ рд▓рд┐рдПред

рдЖрдк рддрдм рд╕реЗ рдЕрдм рддрдХ 6000 рд╕реЗ рдЕрдзрд┐рдХ рдмрд╛рд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдЪреБрдХреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдПрдХ рдЙрдкрдпреЛрдЧреА рд╕реБрд╡рд┐рдзрд╛ рдкрд░ рдХрд┐рд╕реА рдХрд╛ рдзреНрдпрд╛рди рдирд╣реАрдВ рдЧрдпрд╛ рд╣реИ рд╕рдВрд░рдЪрдирд╛рддреНрдордХ рд╕реБрд░рд╛рдЧ, рдЬреЛ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреЗ рд╣реИрдВ:

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐

рдЙрдиреНрд╣реЗрдВ рд╕реБрдиреЗрдВ рдФрд░ рдЖрдкрдХреЗ рдЕрдиреБрд░реЛрдз "рд░реЗрд╢рдореА рдЪрд┐рдХрдиреА рд╣реЛ рдЬрд╛рдПрдВрдЧреЗ"ред ЁЯЩВ

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

рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЕрдиреБрднрд╡ рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░рддреЗ рд╣реБрдП, рдЕрдкрдиреЗ рджрдо рдкрд░ рдПрдХ рдЕрдиреБрдХреВрд▓рди рд╡рд┐рдХрд▓реНрдк рдХреА рддрд▓рд╛рд╢ рдирд╣реАрдВ рдХрд░рдиреА рд╣реЛрдЧреА - рд╣рдо рдЙрд╕реЗ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ, рдХреНрдпрд╛ рдХрд╛рд░рдг рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдХреИрд╕реЗ рд╕рдорд╛рдзрд╛рди рдирд┐рдХрд╛рд▓рд╛ рдЬрд╛рдП. рдЬреЛ рд╣рдордиреЗ рдХрд┐рдпрд╛ред

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐

рдЖрдЗрдП рдЗрди рдорд╛рдорд▓реЛрдВ рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ - рдЙрдиреНрд╣реЗрдВ рдХреИрд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рд╡реЗ рдХрд┐рди рд╕рд┐рдлрд╛рд░рд┐рд╢реЛрдВ рдХреА рдУрд░ рд▓реЗ рдЬрд╛рддреЗ рд╣реИрдВред

рд╡рд┐рд╖рдп рдореЗрдВ рдмреЗрд╣рддрд░ рддрд▓реНрд▓реАрдирддрд╛ рдХреЗ рд▓рд┐рдП, рдЖрдк рдкрд╣рд▓реЗ рд╕рдВрдмрдВрдзрд┐рдд рдмреНрд▓реЙрдХ рдХреЛ рд╕реБрди рд╕рдХрддреЗ рд╣реИрдВ PGConf.Russia 2020 рдкрд░ рдореЗрд░реА рд░рд┐рдкреЛрд░реНрдЯ, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА рдкреНрд░рддреНрдпреЗрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╡рд┐рд╕реНрддреГрдд рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдкрд░ рдЬрд╛рдПрдБ:

#1: рдЗрдВрдбреЗрдХреНрд╕ "рдЕрдВрдбрд░рд╕реЙрд░реНрдЯрд┐рдВрдЧ"

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдХреНрд▓рд╛рдЗрдВрдЯ "рдПрд▓рдПрд▓рд╕реА рдХреЛрд▓реЛрдХреЛрд▓рд┐рдХ" рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдЪрд╛рд▓рд╛рди рджрд┐рдЦрд╛рдПрдВред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> Limit
   -> Sort
      -> Index [Only] Scan [Backward] | Bitmap Heap Scan

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдЗрдВрдбреЗрдХреНрд╕ рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рд╕реЙрд░реНрдЯ рдлрд╝реАрд▓реНрдб рдХреЗ рд╕рд╛рде рд╡рд┐рд╕реНрддреГрдд рдХрд░реЗрдВ.

рдЙрджрд╛рд╣рд░рдг:

CREATE TABLE tbl AS
SELECT
  generate_series(1, 100000) pk  -- 100K "╤Д╨░╨║╤В╨╛╨▓"
, (random() * 1000)::integer fk_cli; -- 1K ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣

CREATE INDEX ON tbl(fk_cli); -- ╨╕╨╜╨┤╨╡╨║╤Б ╨┤╨╗╤П foreign key

SELECT
  *
FROM
  tbl
WHERE
  fk_cli = 1 -- ╨╛╤В╨▒╨╛╤А ╨┐╨╛ ╨║╨╛╨╜╨║╤А╨╡╤В╨╜╨╛╨╣ ╤Б╨▓╤П╨╖╨╕
ORDER BY
  pk DESC -- ╤Е╨╛╤В╨╕╨╝ ╨▓╤Б╨╡╨│╨╛ ╨╛╨┤╨╜╤Г "╨┐╨╛╤Б╨╗╨╡╨┤╨╜╤О╤О" ╨╖╨░╨┐╨╕╤Б╤М
LIMIT 1;

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рдЖрдк рддреБрд░рдВрдд рдиреЛрдЯрд┐рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЗрдВрдбреЗрдХреНрд╕ рджреНрд╡рд╛рд░рд╛ 100 рд╕реЗ рдЕрдзрд┐рдХ рд░рд┐рдХреЙрд░реНрдб рдШрдЯрд╛рдП рдЧрдП рдереЗ, рдЬреЛ рддрдм рд╕рднреА рд╕реЙрд░реНрдЯ рдХрд┐рдП рдЧрдП рдереЗ, рдФрд░ рдлрд┐рд░ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдмрдЪрд╛ рдерд╛ред

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

DROP INDEX tbl_fk_cli_idx;
CREATE INDEX ON tbl(fk_cli, pk DESC); -- ╨┤╨╛╨▒╨░╨▓╨╕╨╗╨╕ ╨║╨╗╤О╤З ╤Б╨╛╤А╤В╨╕╤А╨╛╨▓╨║╨╕

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рдРрд╕реЗ рдЖрджрд┐рдо рдирдореВрдиреЗ рдкрд░ рднреА - 8.5x рддреЗрдЬ рдФрд░ 33x рдХрдо рдкрдврд╝рддрд╛ рд╣реИ. рдкреНрд░рднрд╛рд╡ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдЧрд╛, рдЖрдкрдХреЗ рдкрд╛рд╕ рдкреНрд░рддреНрдпреЗрдХ рдореВрд▓реНрдп рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ "рддрдереНрдп" рд╣реЛрдВрдЧреЗред fk.

рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдРрд╕рд╛ рд╕реВрдЪрдХрд╛рдВрдХ "рдЙрдкрд╕рд░реНрдЧ" рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░реЗрдЧрд╛, рдЬреЛ рдЕрдиреНрдп рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд┐рдЫрд▓реЗ рдПрдХ рд╕реЗ рднреА рдмрджрддрд░ рдирд╣реАрдВ рд╣реИ fk, рдЬрд╣рд╛рдВ рджреНрд╡рд╛рд░рд╛ рдХреНрд░рдордмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ pk рдирд╣реАрдВ рдерд╛ рдФрд░ рдирд╣реАрдВ рд╣реИ (рдЖрдк рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ рдореЗрд░реЗ рд▓реЗрдЦ рдореЗрдВ рдЕрдХреНрд╖рдо рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдЦреЛрдЬрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ). рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдпрд╣ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рджрд╛рди рдХрд░реЗрдЧрд╛ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рджреЗрд╢реА рдХреБрдВрдЬреА рд╕рдорд░реНрдерди рдЗрд╕ рдХреНрд╖реЗрддреНрд░ рджреНрд╡рд╛рд░рд╛ред

# 2: рдЗрдВрдбреЗрдХреНрд╕ рдЪреМрд░рд╛рд╣рд╛ (рдмрд┐рдЯрдореИрдк рдФрд░)

рдХрдм рдХрд░рддрд╛ рд╣реИ

"NJSC Lyutik" рдХреА рдУрд░ рд╕реЗ рд╕рдВрдкрдиреНрди рдХреНрд▓рд╛рдЗрдВрдЯ "LLC Kolocolchik" рдХреЗ рд▓рд┐рдП рд╕рднреА рдЕрдиреБрдмрдВрдз рджрд┐рдЦрд╛рдПрдВред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> BitmapAnd
   -> Bitmap Index Scan
   -> Bitmap Index Scan

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдмрдирд╛рдПрдБ рд╕рдВрдпреБрдХреНрдд рд╕реВрдЪрдХрд╛рдВрдХ рджреЛрдиреЛрдВ рд╕реНрд░реЛрддреЛрдВ рд╕реЗ рдлрд╝реАрд▓реНрдб рджреНрд╡рд╛рд░рд╛ рдпрд╛ рджреВрд╕рд░реЗ рд╕реЗ рдореМрдЬреВрджрд╛ рдлрд╝реАрд▓реНрдб рдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВред

рдЙрджрд╛рд╣рд░рдг:

CREATE TABLE tbl AS
SELECT
  generate_series(1, 100000) pk      -- 100K "╤Д╨░╨║╤В╨╛╨▓"
, (random() *  100)::integer fk_org  -- 100 ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣
, (random() * 1000)::integer fk_cli; -- 1K ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣

CREATE INDEX ON tbl(fk_org); -- ╨╕╨╜╨┤╨╡╨║╤Б ╨┤╨╗╤П foreign key
CREATE INDEX ON tbl(fk_cli); -- ╨╕╨╜╨┤╨╡╨║╤Б ╨┤╨╗╤П foreign key

SELECT
  *
FROM
  tbl
WHERE
  (fk_org, fk_cli) = (1, 999); -- ╨╛╤В╨▒╨╛╤А ╨┐╨╛ ╨║╨╛╨╜╨║╤А╨╡╤В╨╜╨╛╨╣ ╨┐╨░╤А╨╡

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

DROP INDEX tbl_fk_org_idx;
CREATE INDEX ON tbl(fk_org, fk_cli);

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рдпрд╣рд╛рдБ рд▓рд╛рдн рдЫреЛрдЯрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдмрд┐рдЯрдореИрдк рд╣реАрдк рд╕реНрдХреИрди рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдХрд╛рдлреА рдкреНрд░рднрд╛рд╡реА рд╣реИред рд▓реЗрдХрд┐рди рд╡реИрд╕реЗ рднреА 7x рддреЗрдЬ рдФрд░ 2.5x рдХрдо рдкрдврд╝рддрд╛ рд╣реИ.

#3: рдЗрдВрдбреЗрдХреНрд╕ рдХрд╛ рд╕рдВрдпреЛрдЬрди (рдмрд┐рдЯрдореИрдкрдСрд░)

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдореЗрдВ рд╕реНрд╡рдпрдВ рдХреЗ рд╕рд╛рде рдкрд╣рд▓реЗ 20 рд╕рдмрд╕реЗ рдкреБрд░рд╛рдиреЗ "рд╕реНрд╡рдпрдВ" рдпрд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдЕрд╕рд╛рдЗрди рдирд╣реАрдВ рдХрд┐рдП рдЧрдП рдЕрдиреБрд░реЛрдз рджрд┐рдЦрд╛рдПрдВред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> BitmapOr
   -> Bitmap Index Scan
   -> Bitmap Index Scan

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрдШ [рд╕рднреА] рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдерд┐рддрд┐ рдпрд╛ рдмреНрд▓реЙрдХ рдХреЗ рд▓рд┐рдП рдЙрдкрд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред

рдЙрджрд╛рд╣рд░рдг:

CREATE TABLE tbl AS
SELECT
  generate_series(1, 100000) pk  -- 100K "╤Д╨░╨║╤В╨╛╨▓"
, CASE
    WHEN random() < 1::real/16 THEN NULL -- ╤Б ╨▓╨╡╤А╨╛╤П╤В╨╜╨╛╤Б╤В╤М╤О 1:16 ╨╖╨░╨┐╨╕╤Б╤М "╨╜╨╕╤З╤М╤П"
    ELSE (random() * 100)::integer -- 100 ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣
  END fk_own;

CREATE INDEX ON tbl(fk_own, pk); -- ╨╕╨╜╨┤╨╡╨║╤Б ╤Б "╨▓╤А╨╛╨┤╨╡ ╨║╨░╨║ ╨┐╨╛╨┤╤Е╨╛╨┤╤П╤Й╨╡╨╣" ╤Б╨╛╤А╤В╨╕╤А╨╛╨▓╨║╨╛╨╣

SELECT
  *
FROM
  tbl
WHERE
  fk_own = 1 OR -- ╤Б╨▓╨╛╨╕
  fk_own IS NULL -- ... ╨╕╨╗╨╕ "╨╜╨╕╤З╤М╨╕"
ORDER BY
  pk
, (fk_own = 1) DESC -- ╤Б╨╜╨░╤З╨░╨╗╨░ "╤Б╨▓╨╛╨╕"
LIMIT 20;

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

(
  SELECT
    *
  FROM
    tbl
  WHERE
    fk_own = 1 -- ╤Б╨╜╨░╤З╨░╨╗╨░ "╤Б╨▓╨╛╨╕" 20
  ORDER BY
    pk
  LIMIT 20
)
UNION ALL
(
  SELECT
    *
  FROM
    tbl
  WHERE
    fk_own IS NULL -- ╨┐╨╛╤В╨╛╨╝ "╨╜╨╕╤З╤М╨╕" 20
  ORDER BY
    pk
  LIMIT 20
)
LIMIT 20; -- ╨╜╨╛ ╨▓╤Б╨╡╨│╨╛ - 20, ╨▒╨╛╨╗╤М╤И╨╡ ╨╕ ╨╜╨╡ ╨╜╨░╨┤╨╛

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рдордиреЗ рдЗрд╕ рддрдереНрдп рдХрд╛ рд▓рд╛рдн рдЙрдард╛рдпрд╛ рдХрд┐ рдкрд╣рд▓реЗ рдмреНрд▓реЙрдХ рдореЗрдВ рд╕рднреА 20 рдЖрд╡рд╢реНрдпрдХ рд░рд┐рдХреЙрд░реНрдб рддреБрд░рдВрдд рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЧрдП рдереЗ, рдЗрд╕рд▓рд┐рдП рджреВрд╕рд░рд╛, рдЕрдзрд┐рдХ "рдорд╣рдВрдЧреЗ" рдмрд┐рдЯрдореИрдк рд╣реАрдк рд╕реНрдХреИрди рдХреЗ рд╕рд╛рде, рдирд┐рд╖реНрдкрд╛рджрд┐рдд рднреА рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ - рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк 22x рддреЗрдЬ, 44x рдХрдо рдкрдврд╝рддрд╛ рд╣реИ!

рдЗрд╕ рдЕрдиреБрдХреВрд▓рди рдкрджреНрдзрддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддреГрдд рдХрд╣рд╛рдиреА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдкрдврд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдПрд╕рдХреНрдпреВрдПрд▓ рдПрдВрдЯреАрдкреИрдЯрд░реНрди: рд╣рд╛рдирд┐рдХрд╛рд░рдХ рдЬреЙрдЗрди рдФрд░ рдУрдЖрд░рдПрд╕ ╨╕ PostgreSQL Antipatterns: рдирд╛рдо рд╕реЗ рдЦреЛрдЬ рдХреЗ рдкреБрдирд░рд╛рд╡реГрддреНрдд рд╢реЛрдзрди рдХреА рдХрд╣рд╛рдиреА, рдпрд╛ "рдЖрдЧреЗ рдФрд░ рдкреАрдЫреЗ рдХрд╛ рдЕрдиреБрдХреВрд▓рди".

рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рд╕рдВрд╕реНрдХрд░рдг рдХрдИ рдЪрд╛рдмрд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЪрдпрди рдХрд╛ рдЖрджреЗрд╢ рджрд┐рдпрд╛ (рдФрд░ рди рдХреЗрд╡рд▓ const / NULL рдХреА рдПрдХ рдЬреЛрдбрд╝реА рдХреЗ рд▓рд┐рдП) рд▓реЗрдЦ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╣реИ рдПрд╕рдХреНрдпреВрдПрд▓ рд╣рд╛рдЙрдЯреЛ: рдХреНрд╡реЗрд░реА рдореЗрдВ рд╕реАрдзреЗ рдереЛрдбрд╝реА рджреЗрд░ рд▓реВрдк рд▓рд┐рдЦреЗрдВ, рдпрд╛ "рдкреНрд░рд╛рдердорд┐рдХ рддреАрди-рддрд░рдлрд╛".

#4: рд╣рдо рдмрд╣реБрдд рдЬреНрдпрд╛рджрд╛ рдкрдврд╝рддреЗ рд╣реИрдВ

рдХрдм рдХрд░рддрд╛ рд╣реИ

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

"рдФрд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рд╕рдорд╛рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдореЛрддреА рдмрдЯрди рдХреЗ рд╕рд╛рде? " рдлрд┐рд▓реНрдо "рдбрд╛рдпрдордВрдб рд╣реИрдВрдб"

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЙрдкрд░реЛрдХреНрдд рдХрд╛рд░реНрдп рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рддреЗ рд╣реБрдП, рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ 20 рд╕рдмрд╕реЗ рдкреБрд░рд╛рдиреЗ "рдорд╣рддреНрд╡рдкреВрд░реНрдг" рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рджрд┐рдЦрд╛рдПрдВ, рднрд▓реЗ рд╣реА рдЙрдирдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдХреБрдЫ рднреА рд╣реЛред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
   && 5 ├Ч rows < RRbF -- ╨╛╤В╤Д╨╕╨╗╤М╤В╤А╨╛╨▓╨░╨╜╨╛ >80% ╨┐╤А╨╛╤З╨╕╤В╨░╨╜╨╜╨╛╨│╨╛
   && loops ├Ч RRbF > 100 -- ╨╕ ╨┐╤А╨╕ ╤Н╤В╨╛╨╝ ╨▒╨╛╨╗╤М╤И╨╡ 100 ╨╖╨░╨┐╨╕╤Б╨╡╨╣ ╤Б╤Г╨╝╨╝╨░╤А╨╜╨╛

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

[рдЕрдзрд┐рдХ] рд╡рд┐рд╢рд┐рд╖реНрдЯ рдмрдирд╛рдПрдБ WHERE рдХреНрд▓реЙрдЬ рдХреЗ рд╕рд╛рде рдЗрдВрдбреЗрдХреНрд╕ рдпрд╛ рдЗрдВрдбреЗрдХреНрд╕ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВред

рдпрджрд┐ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рд╕реНрдерд┐рддрд┐ рдЖрдкрдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП "рд╕реНрдерд┐рд░" рд╣реИ - рдЕрд░реНрдерд╛рдд рд╡рд┐рд╕реНрддрд╛рд░ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реИ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдореВрд▓реНрдпреЛрдВ рдХреА рд╕реВрдЪреА - WHERE рдЗрдВрдбреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИред рдЗрд╕ рд╢реНрд░реЗрдгреА рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рдмреВрд▓рд┐рдпрди/рдПрдирдо рд╕реНрдерд┐рддрд┐рдпрд╛рдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдлрд┐рдЯ рдмреИрдарддреА рд╣реИрдВред

рдЕрдЧрд░ рдЫрд╛рдирдиреЗ рдХреА рд╕реНрдерд┐рддрд┐ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдорд╛рди рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рд╕реВрдЪрдХрд╛рдВрдХ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ - рдЬреИрд╕рд╛ рдХрд┐ рдмрд┐рдЯрдореИрдк рдФрд░ рдКрдкрд░ рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣реИред

рдЙрджрд╛рд╣рд░рдг:

CREATE TABLE tbl AS
SELECT
  generate_series(1, 100000) pk -- 100K "╤Д╨░╨║╤В╨╛╨▓"
, CASE
    WHEN random() < 1::real/16 THEN NULL
    ELSE (random() * 100)::integer -- 100 ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣
  END fk_own
, (random() < 1::real/50) critical; -- 1:50, ╤З╤В╨╛ ╨╖╨░╤П╨▓╨║╨░ "╨║╤А╨╕╤В╨╕╤З╨╜╨░╤П"

CREATE INDEX ON tbl(pk);
CREATE INDEX ON tbl(fk_own, pk);

SELECT
  *
FROM
  tbl
WHERE
  critical
ORDER BY
  pk
LIMIT 20;

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

CREATE INDEX ON tbl(pk)
  WHERE critical; -- ╨┤╨╛╨▒╨░╨▓╨╕╨╗╨╕ "╤Б╤В╨░╤В╨╕╤З╨╜╨╛╨╡" ╤Г╤Б╨╗╨╛╨▓╨╕╨╡ ╤Д╨╕╨╗╤М╤В╤А╨░╤Ж╨╕╨╕

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпреЛрдЬрдирд╛ рд╕реЗ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЪрд▓реА рдЧрдИ рд╣реИ, рдФрд░ рдЕрдиреБрд░реЛрдз рдмрди рдЧрдпрд╛ рд╣реИ 5 рдЧреБрдирд╛ рддреЗрдЬ.

# 5: рд╡рд┐рд░рд▓ рддрд╛рд▓рд┐рдХрд╛

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдХрд╛рд░реНрдп рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрддрд╛рд░ рдмрдирд╛рдиреЗ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдпрд╛рд╕, рдЬрдм рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЕрджреНрдпрддрди / рд╡рд┐рд▓реЛрдкрди рд░рд┐рдХреЙрд░реНрдб рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ "рдореГрдд" рд░рд┐рдХреЙрд░реНрдб рдХреА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдХрд╛рд░рдг рдмрдирддреЗ рд╣реИрдВред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
   && loops ├Ч (rows + RRbF) < (shared hit + shared read) ├Ч 8
      -- ╨┐╤А╨╛╤З╨╕╤В╨░╨╜╨╛ ╨▒╨╛╨╗╤М╤И╨╡ 1KB ╨╜╨░ ╨║╨░╨╢╨┤╤Г╤О ╨╖╨░╨┐╨╕╤Б╤М
   && shared hit + shared read > 64

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдХрд░реЗрдВ рд╡реИрдХреНрдпреВрдо [рдкреВрд░реНрдг] рдпрд╛ рдкрд░реНрдпрд╛рдкреНрдд рд░реВрдк рд╕реЗ рд▓рдЧрд╛рддрд╛рд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ рдСрдЯреЛрд╡реИрдХреНрдпреВрдо рд╕рд╣рд┐рдд рдЗрд╕рдХреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдареАрдХ рдХрд░рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП.

рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдРрд╕реА рд╕рдорд╕реНрдпрд╛рдПрдВ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рд╕реЗ рдмреБрд▓рд╛рдП рдЬрд╛рдиреЗ рдкрд░ рдЦрд░рд╛рдм рдХреНрд╡реЗрд░реА рд▓реЗрдЖрдЙрдЯ рдХреЗ рдХрд╛рд░рдг рд╣реЛрддреА рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ рдЬрд┐рди рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╣реИ PostgreSQL Antipatterns: "рдореГрдд" рдХреА рднреАрдбрд╝ рд╕реЗ рд▓рдбрд╝рдирд╛.

рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдпрд╣ рд╕рдордЭрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ VACUUM FULL рд╣рдореЗрд╢рд╛ рдорджрдж рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ред рдРрд╕реЗ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд▓реЗрдЦ рд╕реЗ рдПрд▓реНрдЧреЛрд░рд┐рдердо рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред DBA: рдЬрдм VACUUM рдкрд╛рд╕ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЯреЗрдмрд▓ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕рд╛рдл рдХрд░рддреЗ рд╣реИрдВ.

#6: рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ "рдордзреНрдп" рд╕реЗ рдкрдврд╝рдирд╛

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдиреНрд╣реЛрдВрдиреЗ рдереЛрдбрд╝рд╛ рдкрдврд╝рд╛, рдФрд░ рд╕рдм рдХреБрдЫ рдЕрдиреБрдХреНрд░рдорд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдЙрдиреНрд╣реЛрдВрдиреЗ рдХрд┐рд╕реА рдХреЛ рднреА рдЕрддрд┐рд░рд┐рдХреНрдд рдлрд╝рд┐рд▓реНрдЯрд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ - рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА, рд╣рдо рдЬрд┐рддрдиреЗ рдкреГрд╖реНрда рдЪрд╛рд╣реЗрдВрдЧреЗ, рдЙрд╕рд╕реЗ рдХрд╣реАрдВ рдЕрдзрд┐рдХ рдкреГрд╖реНрда рдкрдврд╝реЗ рдЧрдПред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> Index [Only] Scan [Backward]
   && loops ├Ч (rows + RRbF) < (shared hit + shared read) ├Ч 8
      -- ╨┐╤А╨╛╤З╨╕╤В╨░╨╜╨╛ ╨▒╨╛╨╗╤М╤И╨╡ 1KB ╨╜╨░ ╨║╨░╨╢╨┤╤Г╤О ╨╖╨░╨┐╨╕╤Б╤М
   && shared hit + shared read > 64

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рд╕реВрдЪрдХрд╛рдВрдХ рдХреА рд╕рдВрд░рдЪрдирд╛ рдФрд░ рдХреНрд╡реЗрд░реА рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкреНрд░рдореБрдЦ рдХреНрд╖реЗрддреНрд░реЛрдВ рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ - рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ, рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рднрд╛рдЧ рд╕реЗрдЯ рдирд╣реАрдВ рд╣реИ. рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдПрдХ рд╕рдорд╛рди рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рдЙрдкрд╕рд░реНрдЧ рдлрд╝реАрд▓реНрдб рдХреЗ рдмрд┐рдирд╛, рдпрд╛ рдЙрдирдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдХрд░рдирд╛ рд╕реАрдЦреЗрдВ.

рдЙрджрд╛рд╣рд░рдг:

CREATE TABLE tbl AS
SELECT
  generate_series(1, 100000) pk      -- 100K "╤Д╨░╨║╤В╨╛╨▓"
, (random() *  100)::integer fk_org  -- 100 ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣
, (random() * 1000)::integer fk_cli; -- 1K ╤А╨░╨╖╨╜╤Л╤Е ╨▓╨╜╨╡╤И╨╜╨╕╤Е ╨║╨╗╤О╤З╨╡╨╣

CREATE INDEX ON tbl(fk_org, fk_cli); -- ╨▓╤Б╨╡ ╨┐╨╛╤З╤В╨╕ ╨║╨░╨║ ╨▓ #2
-- ╤В╨╛╨╗╤М╨║╨╛ ╨▓╨╛╤В ╨╛╤В╨┤╨╡╨╗╤М╨╜╤Л╨╣ ╨╕╨╜╨┤╨╡╨║╤Б ╨┐╨╛ fk_cli ╨╝╤Л ╤Г╨╢╨╡ ╨┐╨╛╤Б╤З╨╕╤В╨░╨╗╨╕ ╨╗╨╕╤И╨╜╨╕╨╝ ╨╕ ╤Г╨┤╨░╨╗╨╕╨╗╨╕

SELECT
  *
FROM
  tbl
WHERE
  fk_cli = 999 -- ╨░ fk_org ╨╜╨╡ ╨╖╨░╨┤╨░╨╜╨╛, ╤Е╨╛╤В╤П ╤Б╤В╨╛╨╕╤В ╨▓ ╨╕╨╜╨┤╨╡╨║╤Б╨╡ ╤А╨░╨╜╤М╤И╨╡
LIMIT 20;

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рднреА рд╕рдм рдХреБрдЫ рдареАрдХ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХрд┐рд╕реА рддрд░рд╣ рд╕рдВрджреЗрд╣рд╛рд╕реНрдкрдж - тАЛтАЛрдкреНрд░рддреНрдпреЗрдХ 20 рд░рд┐рдХреЙрд░реНрдб рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛ рдХреЗ 4 рдкреГрд╖реНрда рдШрдЯрд╛рдП рдЬрд╛рдиреЗ рдереЗ, 32KB рдкреНрд░рддрд┐ рд░рд┐рдХреЙрд░реНрдб - рдХреНрдпрд╛ рдпрд╣ рдмреЛрд▓реНрдб рдирд╣реАрдВ рд╣реИ? рд╣рд╛рдВ рдФрд░ рдЗрдВрдбреЗрдХреНрд╕ рдирд╛рдо tbl_fk_org_fk_cli_idx рд╡рд┐рдЪрд╛рд░ рдХреА рдУрд░ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИред

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

CREATE INDEX ON tbl(fk_cli);

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рдЕрдЪрд╛рдирдХ - рдкрдврд╝рдиреЗ рдореЗрдВ 10 рдЧреБрдирд╛ рддреЗрдЬ рдФрд░ 4 рдЧреБрдирд╛ рдХрдо!

рдЗрдВрдбреЗрдХреНрд╕ рдХреЗ рдЕрдХреНрд╖рдо рдЙрдкрдпреЛрдЧ рдХреЗ рдЕрдзрд┐рдХ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдЖрд▓реЗрдЦ рджреЗрдЦреЗрдВ рдбреАрдмреАрдП: рдмреЗрдХрд╛рд░ рдЗрдВрдбреЗрдХреНрд╕ рдЦреЛрдЬреЗрдВ.

#7: рд╕реАрдЯреАрдИ ├Ч рд╕реАрдЯреАрдИ

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдЕрдиреБрд░реЛрдз рдореЗрдВ "рд╡рд╕рд╛" рд╕реАрдЯреАрдИ рд╕реНрдХреЛрд░ рдХрд┐рдпрд╛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рд╕реЗ, рдФрд░ рдлрд┐рд░ рдЙрдирдХреЗ рдмреАрдЪ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ JOIN.

рдорд╛рдорд▓рд╛ v12 рд╕реЗ рдиреАрдЪреЗ рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдпрд╛ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИ WITH MATERIALIZED.

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> CTE Scan
   && loops > 10
   && loops ├Ч (rows + RRbF) > 10000
      -- ╤Б╨╗╨╕╤И╨║╨╛╨╝ ╨▒╨╛╨╗╤М╤И╨╛╨╡ ╨┤╨╡╨║╨░╤А╤В╨╛╨▓╨╛ ╨┐╤А╨╛╨╕╨╖╨▓╨╡╨┤╨╡╨╜╨╕╨╡ CTE

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдЕрдиреБрд░реЛрдз рдХрд╛ рд╕рд╛рд╡рдзрд╛рдиреАрдкреВрд░реНрд╡рдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ рдХреНрдпрд╛ рдпрд╣рд╛рдВ рд╕реАрдЯреАрдИ рдХреА рдмрд┐рд▓реНрдХреБрд▓ рдЬрд░реВрд░рдд рд╣реИ? рдпрджрд┐ рд╣рд╛рдВ, рддреЛ hstore/json рдореЗрдВ "рд╢рдмреНрджрдХреЛрд╢" рд▓рд╛рдЧреВ рдХрд░реЗрдВ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдореЙрдбрд▓ рдХреЗ рдЕрдиреБрд╕рд╛рд░ PostgreSQL рдПрдВрдЯреАрдкреИрдЯрд░реНрди: рдбрд┐рдХреНрд╢рдирд░реА рд╣рд┐рдЯ рд╣реИрд╡реА рдЬреЙрдЗрди.

# 8: рдбрд┐рд╕реНрдХ рдкрд░ рд╕реНрд╡реИрдк рдХрд░реЗрдВ (рдЕрд╕реНрдерд╛рдпреА рд░реВрдк рд╕реЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛)

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд░рд┐рдХреЙрд░реНрдб рдХреА рдПрдХ рдмрд╛рд░ рдХреА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ (рд╕реЙрд░реНрдЯрд┐рдВрдЧ рдпрд╛ рдпреВрдирд┐рдХрд╛рдЗрдЬреЗрд╢рди) рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрд╡рдВрдЯрд┐рдд рдореЗрдореЛрд░реА рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> *
   && temp written > 0

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдпрджрд┐ рдСрдкрд░реЗрд╢рди рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдореЗрдореЛрд░реА рдХреА рдорд╛рддреНрд░рд╛ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕реЗрдЯ рдорд╛рди рд╕реЗ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИ рдХрд╛рдо_рдореЗрдо, рдЗрд╕реЗ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛рдПред рдЖрдк рддреБрд░рдВрдд рд╕рднреА рдХреЗ рд▓рд┐рдП рдХреЙрдиреНрдлрд┐рдЧрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ SET [LOCAL] рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЕрдиреБрд░реЛрдз/рд▓реЗрдирджреЗрди рдХреЗ рд▓рд┐рдПред

рдЙрджрд╛рд╣рд░рдг:

SHOW work_mem;
-- "16MB"

SELECT
  random()
FROM
  generate_series(1, 1000000)
ORDER BY
  1;

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рдо рддрдп рдХрд░рддреЗ рд╣реИрдВ:

SET work_mem = '128MB'; -- ╨┐╨╡╤А╨╡╨┤ ╨▓╤Л╨┐╨╛╨╗╨╜╨╡╨╜╨╕╨╡╨╝ ╨╖╨░╨┐╤А╨╛╤Б╨░

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╕реНрдкрд╖реНрдЯ рдХрд╛рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдХреЗрд╡рд▓ рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдбрд┐рд╕реНрдХ рдХрд╛ рдирд╣реАрдВ, рддреЛ рдХреНрд╡реЗрд░реА рдмрд╣реБрдд рддреЗрдЬ рд╣реЛрдЧреАред рд╡рд╣реАрдВ, рд▓реЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдПрдЪрдбреАрдбреА рд╕реЗ рднреА рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рдмрд╣реБрдд рд╕рд╛рд░реА рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рд╕реЗ рд╣рдореЗрд╢рд╛ рдХрд╛рдо рдирд╣реАрдВ рдЪрд▓реЗрдЧрд╛ - рдпрд╣ рдмрд╕ рд╕рднреА рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реЛрдЧрд╛ред

#9: рдЕрдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдЖрдБрдХрдбрд╝реЗ

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдмреЗрд╕ рдореЗрдВ рдПрдХ рдмрд╛рд░ рдореЗрдВ рдмрд╣реБрдд рдХреБрдЫ рдбрд╛рд▓рд╛ рдЧрдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЙрдирдХреЗ рдкрд╛рд╕ рдЗрд╕реЗ рдЪрд▓рд╛рдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рдерд╛ ANALYZE.

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
   && ratio >> 10

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рд╣реА рдЦрд░реНрдЪ рдХрд░реЗрдВ ANALYZE.

рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ PostgreSQL Antipatterns: рдЖрдБрдХрдбрд╝реЗ рд╣рд░ рдЪреАрдЬ рдХреЗ рдкреНрд░рдореБрдЦ рд╣реИрдВ.

#10: "рдХреБрдЫ рдЧрд▓рдд рд╣реЛ рдЧрдпрд╛"

рдХрдм рдХрд░рддрд╛ рд╣реИ

рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзреА рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рдПрдХ рд▓реЙрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рдерд╛, рдпрд╛ рдкрд░реНрдпрд╛рдкреНрдд CPU/рд╣рд╛рдЗрдкрд░рд╡рд╛рдЗрдЬрд╝рд░ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рд╕рдВрд╕рд╛рдзрди рдирд╣реАрдВ рдереЗред

рдХреИрд╕реЗ рдкрд╣рдЪрд╛рдиреЗрдВ

-> *
   && (shared hit / 8K) + (shared read / 1K) < time / 1000
      -- RAM hit = 64MB/s, HDD read = 8MB/s
   && time > 100ms -- ╤З╨╕╤В╨░╨╗╨╕ ╨╝╨░╨╗╨╛, ╨╜╨╛ ╤Б╨╗╨╕╤И╨║╨╛╨╝ ╨┤╨╛╨╗╨│╨╛

рдЕрдиреБрд╢рдВрд╕рд╛рдПрдБ

рдПрдХ рдмрд╛рд╣рд░реА рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВ рдирд┐рдЧрд░рд╛рдиреА рдкреНрд░рдгрд╛рд▓реА рдЕрд╡рд░реБрджреНрдз рдпрд╛ рдЕрд╕рд╛рдорд╛рдиреНрдп рд╕рдВрд╕рд╛рдзрди рдЦрдкрдд рдХреЗ рд▓рд┐рдП рд╕рд░реНрд╡рд░ред рд╣рдо рд╕реИрдХрдбрд╝реЛрдВ рд╕рд░реНрд╡рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЖрдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рдЕрдкрдиреЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд╣рд▓реЗ рд╣реА рдмрд╛рдд рдХрд░ рдЪреБрдХреЗ рд╣реИрдВред рдпрд╣рд╛рдВ ╨╕ рдпрд╣рд╛рдВ.

рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐
рдмреАрдорд╛рд░ рдПрд╕рдХреНрдпреВрдПрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╡реНрдпрдВрдЬрди рд╡рд┐рдзрд┐

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

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