рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ

рдзреЗрд░реИ рдорд╣рд┐рдирд╛ рдЕрдШрд┐ рд╣рд╛рдореАрд▓реЗ рдШреЛрд╖рдгрд╛ рдЧрд░реНтАНрдпреМрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.tensor.ru - рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдХреНрд╡реЗрд░реА рдпреЛрдЬрдирд╛рд╣рд░реВ рдкрд╛рд░реНрд╕рд┐рдЩ рд░ рднрд┐рдЬреБрдЕрд▓рд╛рдЗрдЬ рдЧрд░реНрдиреЗ рд╕реЗрд╡рд╛ PostgreSQL рдорд╛ред

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ

рддрд┐рдиреАрд╣рд░реВрдХреЛ рдХреБрд░рд╛ рд╕реБрдиреНрдиреБрд╣реЛрд╕реН рд░ рддрдкрд╛рдИрдВрдХрд╛ рдЕрдиреБрд░реЛрдзрд╣рд░реВ тАЬрдЪрд┐рд▓реНрд▓реЛ рд░ рд░реЗрд╢рдореАтАЭ рд╣реБрдиреЗрдЫрдиреНред ЁЯЩВ

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

рдпрд╕ рдЕрд╡рд╕реНрдерд╛рдорд╛, рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд▓реЗ рдЖрдлреНрдиреИ рдЕрдиреБрднрд╡рдорд╛ рднрд░ рдкрд░реНрджреИ, рдЖрдлреНрдиреИ рд▓рд╛рдЧрд┐ рдЕрдиреБрдХреВрд▓рди рд╡рд┐рдХрд▓реНрдк рдЦреЛрдЬреНрдиреБ рдкрд░реНрджреИрди - рд╣рд╛рдореА рдЙрд╣рд╛рдБрд▓рд╛рдИ рдпрд╣рд╛рдБ рдХреЗ рднрдЗрд░рд╣реЗрдХреЛ рдЫ, рдХрд╛рд░рдг рдХреЗ рд╣реБрди рд╕рдХреНрдЫ, рд░ рд╕рдорд╛рдзрд╛рди рдХрд╕рд░реА рдкреБрдЧреНрдиреЗред рд╣рд╛рдореАрд▓реЗ рддреНрдпрд╣реА рдЧрд░реНрдпреМрдВред

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ

рдпреА рдорд╛рдорд┐рд▓рд╛рд╣рд░реВрд▓рд╛рдИ рдирдЬрд┐рдХрдмрд╛рдЯ рд╣реЗрд░реМрдВ - рддрд┐рдиреАрд╣рд░реВ рдХрд╕рд░реА рдкрд░рд┐рднрд╛рд╖рд┐рдд рдЫрдиреН рд░ рддрд┐рдиреАрд╣рд░реВрд▓реЗ рдХрд╕реНрддреЛ рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ рдиреЗрддреГрддреНрд╡ рдЧрд░реНрдЫрдиреНред

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

#1: рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ "рдЕрдгреНрдбрд░рд╕рд░реНрдЯрд┐рдЩ"

рдЬрдм рдЙрдареНрдЫ

рдЧреНрд░рд╛рд╣рдХ "LLC Kolokolchik" рдХреЛ рд▓рд╛рдЧрд┐ рдирд╡реАрдирддрдо рдЗрдирднреНрд╡рд╛рдЗрд╕ рджреЗрдЦрд╛рдЙрдиреБрд╣реЛрд╕реНред

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

-> 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;

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рддрдкрд╛рдИрдВрд▓реЗ рддреБрд░реБрдиреНрддреИ рдпрд╛рдж рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ рдХрд┐ 100 рднрдиреНрджрд╛ рдмрдвреА рд░реЗрдХрд░реНрдбрд╣рд░реВ рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛рдмрд╛рдЯ рдШрдЯрд╛рдЗрдПрдХреЛ рдерд┐рдпреЛ, рдЬреБрди рддреНрдпрд╕рдкрдЫрд┐ рд╕рдмреИ рдХреНрд░рдордмрджреНрдз рдЧрд░рд┐рдПрдХреЛ рдерд┐рдпреЛ, рд░ рддреНрдпрд╕рдкрдЫрд┐ рдорд╛рддреНрд░ рдПрдХ рдорд╛рддреНрд░ рдмрд╛рдБрдХреА рдерд┐рдпреЛред

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рдпрд╕реНрддреЛ рдЖрджрд┐рдо рдирдореВрдирд╛рдорд╛ рдкрдирд┐ - рео.рел рдЧреБрдгрд╛ рдЫрд┐рдЯреЛ рд░ рейрей рдЧреБрдгрд╛ рдХрдо рдкрдвреНрдиреЗред рдкреНрд░рддреНрдпреЗрдХ рдорд╛рдирдХреЛ рд▓рд╛рдЧрд┐ рддрдкрд╛рдИрд╕рдБрдЧ рдЬрддрд┐ рдзреЗрд░реИ "рддрдереНрдпрд╣рд░реВ" рд╣реБрдиреНрдЫрдиреН, рдкреНрд░рднрд╛рд╡ рддреНрдпрддрд┐ рдиреИ рд╕реНрдкрд╖реНрдЯ рд╣реБрдиреНрдЫ fk.

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

#2: рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдкреНрд░рддрд┐рдЪреНрдЫреЗрджрди (рдмрд┐рдЯрдореНрдпрд╛рдкрдПрдиреНрдб)

рдЬрдм рдЙрдареНрдЫ

рдЧреНрд░рд╛рд╣рдХ "LLC Kolokolchik" рдХреЛ рд▓рд╛рдЧрд┐ рд╕рдмреИ рд╕рдореНрдЭреМрддрд╛рд╣рд░реВ рджреЗрдЦрд╛рдЙрдиреБрд╣реЛрд╕реН, "NAO Buttercup" рдХреЛ рддрд░реНрдлрдмрд╛рдЯ рд╕рдорд╛рдкреНрдд рднрдпреЛред

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

-> 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); -- ╨╛╤В╨▒╨╛╤А ╨┐╨╛ ╨║╨╛╨╜╨║╤А╨╡╤В╨╜╨╛╨╣ ╨┐╨░╤А╨╡

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рдпрд╣рд╛рдБ рднреБрдХреНрддрд╛рдиреА рд╕рд╛рдиреЛ рдЫ, рдХрд┐рдирдХрд┐ рдмрд┐рдЯрдореНрдпрд╛рдк рд╣реАрдк рд╕реНрдХреНрдпрд╛рди рдЖрдлреИрдВрдорд╛ рдзреЗрд░реИ рдкреНрд░рднрд╛рд╡рдХрд╛рд░реА рдЫред рддрд░ рдЬреЗ рднрдП рдкрдирд┐ рео.рел рдЧреБрдгрд╛ рдЫрд┐рдЯреЛ рд░ рейрей рдЧреБрдгрд╛ рдХрдо рдкрдвреНрдиреЗ.

#3: рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛рд╣рд░реВ рдорд░реНрдЬ рдЧрд░реНрдиреБрд╣реЛрд╕реН (BitmapOr)

рдЬрдм рдЙрдареНрдЫ

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

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

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

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

╨Ш╤Б╨┐╨╛╨╗╤М╨╖╨╛╨▓╨░╤В╤М рдпреБрдирд┐рдпрди [рд╕рдмреИ] рд╕рд░реНрддрд╣рд░реВрдХреЛ рдкреНрд░рддреНрдпреЗрдХ OR-рдмреНрд▓рдХрд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╕рдмрдХреНрд╡реЗрд░реАрд╣рд░реВ рд╕рдВрдпреЛрдЬрди рдЧрд░реНрдиред

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

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;

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

(
  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, ╨▒╨╛╨╗╤М╤И╨╡ ╨╕ ╨╜╨╡ ╨╜╨░╨┤╨╛

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

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

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

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

#4: рд╣рд╛рдореА рдзреЗрд░реИ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЪреАрдЬрд╣рд░реВ рдкрдвреНрдЫреМрдВ

рдЬрдм рдЙрдареНрдЫ

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

"рд░ рддрдкрд╛рдИрдВрд╕рдБрдЧ рдПрдЙрдЯреИ рдЫреИрди, рддрд░ Mother-of-perl рдмрдЯрдирд╣рд░реВрд╕рдБрдЧ? " рдлрд┐рд▓реНрдо "рдж рдбрд╛рдпрдордВрдб рдЖрд░реНрдо"

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

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

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

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

[рдЕрдзрд┐рдХ] рд╡рд┐рд╢реЗрд╖ рдмрдирд╛рдЙрдиреБрд╣реЛрд╕реН WHERE рдЕрд╡рд╕реНрдерд╛рдХреЛ рд╕рд╛рде рд╕реВрдЪрдХрд╛рдВрдХ рд╡рд╛ рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛рдорд╛ рдердк рдХреНрд╖реЗрддреНрд░рд╣рд░реВ рд╕рдорд╛рд╡реЗрд╢ рдЧрд░реНрдиреБрд╣реЛрд╕реНред

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

рдпрджрд┐ рдлрд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдЕрд╡рд╕реНрдерд╛ рд╡рд┐рднрд┐рдиреНрди рдЕрд░реНрде рд▓рд┐рди рд╕рдХреНрдЫ, рддреНрдпрд╕рдкрдЫрд┐ рдпреА рдХреНрд╖реЗрддреНрд░рд╣рд░реВрд╕рдБрдЧ рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдЧрд░реНрди рд░рд╛рдореНрд░реЛ рдЫ - Bitmap рд░ рдорд╛рдерд┐рдХреЛ рдЕрд╡рд╕реНрдерд╛рдорд╛ рдЬрд╕реНрддреИред

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

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;

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рддрдкрд╛рдИрдВрд▓реЗ рджреЗрдЦреНрди рд╕рдХреНрдиреБрд╣реБрдиреЗ рд░реВрдкрдорд╛, рдлрд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдпреЛрдЬрдирд╛рдмрд╛рдЯ рдкреВрд░реНрдг рд░реВрдкрдорд╛ рдЧрд╛рдпрдм рднрдПрдХреЛ рдЫ, рд░ рдЕрдиреБрд░реЛрдз рднрдПрдХреЛ рдЫ 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

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

рдореНрдпрд╛рдиреБрдЕрд▓ рд░реВрдкрдорд╛ рдирд┐рдпрдорд┐рдд рд░реВрдкрдорд╛ рд▓рд┐рдиреБрд╣реЛрд╕реН рднреНрдпрд╛рдХреБрдо [рдкреВрд░реНрдг] рд╡рд╛ рдкрд░реНрдпрд╛рдкреНрдд рд░реВрдкрдорд╛ рд▓рдЧрд╛рддрд╛рд░ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреБрд╣реЛрд╕реН autovacuum рдпрд╕рдХреЛ рдкреНрдпрд╛рд░рд╛рдорд┐рдЯрд░рд╣рд░реВ рдлрд╛рдЗрди-рдЯреНрдпреВрди рдЧрд░реЗрд░, рд╕рд╣рд┐рдд рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рд▓рд╛рдЧреА.

рдзреЗрд░реИ рдЬрд╕реЛ рдХреЗрд╕рд╣рд░реВрдорд╛, рдпрд╕реНрддрд╛ рд╕рдорд╕реНрдпрд╛рд╣рд░реВ рдЦрд░рд╛рдм рдХреНрд╡реЗрд░реА рд╕рдВрд░рдЪрдирд╛рдХреЛ рдХрд╛рд░рдгрд▓реЗ рдЧрд░реНрджрд╛ рд╣реБрдиреНрдЫ рдЬрдм рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХрдмрд╛рдЯ рдХрд▓ рдЧрд░реНрджрд╛ рдЫрд▓рдлрд▓ рдЧрд░рд┐рдПрдХреЛ рдерд┐рдпреЛред 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;

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

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

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

CREATE INDEX ON tbl(fk_cli);

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рдЕрдЪрд╛рдирдХ - 10 рдкрдЯрдХ рдЫрд┐рдЯреЛ, рд░ 4 рдкрдЯрдХ рдХрдо рдкрдвреНрди!

рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛рдХреЛ рдЕрдкреНрд░рднрд╛рд╡реА рдкреНрд░рдпреЛрдЧрдХреЛ рдЕрд╡рд╕реНрдерд╛рдХрд╛ рдЕрдиреНрдп рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рд▓реЗрдЦрдорд╛ рджреЗрдЦреНрди рд╕рдХрд┐рдиреНрдЫ DBA: рдмреЗрдХрд╛рд░ рд╕реВрдЪрдХрд╛рдВрдХрд╣рд░реВ рдлреЗрд▓рд╛ рдкрд╛рд░реНрджреИ.

#7: CTE ├Ч CTE

рдЬрдм рдЙрдареНрдЫ

рдЕрдиреБрд░реЛрдзрдорд╛ рд╕реНрдХреЛрд░ "рдореЛрдЯреЛ" CTE рд╡рд┐рднрд┐рдиреНрди рддрд╛рд▓рд┐рдХрд╛рд╣рд░реВрдмрд╛рдЯ, рд░ рддреНрдпрд╕рдкрдЫрд┐ рддрд┐рдиреАрд╣рд░реВ рдмреАрдЪ рдпреЛ рдЧрд░реНрдиреЗ рдирд┐рд░реНрдгрдп рдЧрд░рд┐рдпреЛ JOIN.

рдХреЗрд╕ v12 рдореБрдирд┐рдХрд╛ рд╕рдВрд╕реНрдХрд░рдгрд╣рд░реВ рд╡рд╛ рдЕрдиреБрд░реЛрдзрд╣рд░реВрд╕рдБрдЧ рд╕рд╛рдиреНрджрд░реНрднрд┐рдХ рдЫ WITH MATERIALIZED.

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

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

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

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

#8: рдбрд┐рд╕реНрдХрдорд╛ рд╕реНрд╡реИрдк рдЧрд░реНрдиреБрд╣реЛрд╕реН (рддрд╛рдк рд▓реЗрдЦрд┐рдПрдХреЛ)

рдЬрдм рдЙрдареНрдЫ

рдПрдХ рдкрдЯрдХрдХреЛ рдкреНрд░рд╢реЛрдзрди (рдХреНрд░рдордмрджреНрдз рд╡рд╛ рд╡рд┐рд╢рд┐рд╖реНрдЯреАрдХрд░рдг) рдареВрд▓реЛ рд╕рдВрдЦреНрдпрд╛рдорд╛ рд░реЗрдХрд░реНрдбрд╣рд░реВ рдпрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдЫреБрдЯреНрдпрд╛рдЗрдПрдХреЛ рдореЗрдореЛрд░реАрдорд╛ рдлрд┐рдЯ рд╣реБрдБрджреИрдиред

рдХрд╕рд░реА рдкрд╣рд┐рдЪрд╛рди рдЧрд░реНрдиреЗ

-> *
   && temp written > 0

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

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

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

SHOW work_mem;
-- "16MB"

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

рд╕рдЪреНрдпрд╛рдЙрдБрджреИ:

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

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
[explan.tensor.ru рдорд╛ рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН]

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

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

#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 -- ╤З╨╕╤В╨░╨╗╨╕ ╨╝╨░╨╗╨╛, ╨╜╨╛ ╤Б╨╗╨╕╤И╨║╨╛╨╝ ╨┤╨╛╨╗╨│╨╛

рд╕рд┐рдлрд╛рд░рд┐рд╕рд╣рд░реВ

рдмрд╛рд╣реНрдп рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН рдирд┐рдЧрд░рд╛рдиреА рдкреНрд░рдгрд╛рд▓реА рдЕрд╡рд░реБрджреНрдз рд╡рд╛ рдЕрд╕рд╛рдорд╛рдиреНрдп рд╕реНрд░реЛрдд рдЦрдкрдд рдХреЛ рд▓рд╛рдЧреА рд╕рд░реНрднрд░ред рд╣рд╛рдореАрд▓реЗ рд╕рдпреМрдВ рд╕рд░реНрднрд░рд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рдпрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛рд▓рд╛рдИ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдЧрд░реНрдиреЗ рд╣рд╛рдореНрд░реЛ рд╕рдВрд╕реНрдХрд░рдгрдХреЛ рдмрд╛рд░реЗрдорд╛ рдХреБрд░рд╛ рдЧрд░рд┐рд╕рдХреЗрдХрд╛ рдЫреМрдВ рдпрд╣рд╛рдБ ╨╕ рдпрд╣рд╛рдБ.

рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ
рдмрд┐рд░рд╛рдореА SQL рдкреНрд░рд╢реНрдирд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡реНрдпрдЮреНрдЬрдирд╣рд░реВ

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

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