рдкреАрдХреЗ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░рдирд╛

рдРрд╕реА рд╕реНрдерд┐рддрд┐рдпрд╛рдБ рд╣реЛрддреА рд╣реИрдВ рдЬрдм рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдЕрджреНрд╡рд┐рддреАрдп рд╕реВрдЪрдХрд╛рдВрдХ рдореЗрдВ, рдХрд┐рд╕реА рдЪреВрдХ рдХреЗ рдХрд╛рд░рдг, рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд░рд┐рдХреЙрд░реНрдб рдХреЗ рдкреВрд░реНрдг рдХреНрд▓реЛрди рд╢рд╛рдорд┐рд▓ рдХрд░ рджрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред

рдкреАрдХреЗ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░рдирд╛

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХрд╛рд▓рд╛рдиреБрдХреНрд░рдорд┐рдХ рдореАрдЯреНрд░рд┐рдХ рдХреЗ рдорд╛рди COPY рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ PostgreSQL рдореЗрдВ рд▓рд┐рдЦреЗ рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЕрдЪрд╛рдирдХ рд╡рд┐рдлрд▓рддрд╛ рд╣реЛрддреА рд╣реИ, рдФрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рди рдбреЗрдЯрд╛ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдлрд┐рд░ рд╕реЗ рдЖрддрд╛ рд╣реИред

рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХреНрд▓реЛрдиреЛрдВ рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХреИрд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдПрдВ?

рдЬрдм рдкреАрдХреЗ рдорджрджрдЧрд╛рд░ рдирд╣реАрдВ рд╣реИ

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

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рд╕реНрд░реЛрдд рдкреНрд░рдгрд╛рд▓реА рдХреА рд╕рдЯреАрдХрддрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдлрд╝реАрд▓реНрдб рдХреА рд╕рдЯреАрдХрддрд╛ рд╕реЗ рдЕрдзрд┐рдХ рд╣реИ:

metric   | ts                  | data
--------------------------------------------------
cpu.busy | 2019-12-20 00:00:00 | {"value" : 12.34}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 10}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 11.2}
cpu.busy | 2019-12-20 00:00:03 | {"value" : 15.7}

рдХреНрдпрд╛ рддреБрдордиреЗ рдзреНрдпрд╛рди рджрд┐рдпрд╛? 00:00:02 рдХреЗ рдмрдЬрд╛рдп рдЙрд▓рдЯреА рдЧрд┐рдирддреА рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЯреАрдПрд╕ рдХреЗ рд╕рд╛рде рдПрдХ рд╕реЗрдХрдВрдб рдкрд╣рд▓реЗ рджрд░реНрдЬ рдХреА рдЧрдИ рдереА, рд▓реЗрдХрд┐рди рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ рдХрд╛рдлреА рдорд╛рдиреНрдп рд░рд╣реА (рдЖрдЦрд┐рд░рдХрд╛рд░, рдбреЗрдЯрд╛ рдорд╛рди рдЕрд▓рдЧ рд╣реИрдВ!)ред

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

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

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

"рдХреНрд▓реЛрдирд┐рдХ рдпреБрджреНрдз рд╢реБрд░реВ рд╣реЛ рдЧрдпрд╛ рд╣реИ"

рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рджреБрд░реНрдШрдЯрдирд╛ рд╣реБрдИ, рдФрд░ рдЕрдм рд╣рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдирд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдкреАрдХреЗ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░рдирд╛

рдЖрдЗрдП рдореВрд▓ рдбреЗрдЯрд╛ рдХрд╛ рдореЙрдбрд▓ рдмрдирд╛рдПрдВ:

CREATE TABLE tbl(k text, v integer);

INSERT INTO tbl
VALUES
  ('a', 1)
, ('a', 3)
, ('b', 2)
, ('b', 2) -- oops!
, ('c', 3)
, ('c', 3) -- oops!!
, ('c', 3) -- oops!!
, ('d', 4)
, ('e', 5)
;

рдпрд╣рд╛рдВ рд╣рдорд╛рд░рд╛ рд╣рд╛рде рддреАрди рдмрд╛рд░ рдХрд╛рдВрдкрд╛, Ctrl+V рдЕрдЯрдХ рдЧрдпрд╛ рдФрд░ рдЕрдм...

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

рдФрд░ рдПрдХ рдРрд╕рд╛ рддрд░реАрдХрд╛ рд╣реИ - рдпрд╣ рд╕реАрдЯреАрдЖрдИрдбреА тАЛтАЛрджреНрд╡рд╛рд░рд╛ рд╕рдВрдмреЛрдзрд┐рдд рдХрд░рдирд╛, рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд░рд┐рдХреЙрд░реНрдб рдХрд╛ рднреМрддрд┐рдХ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ред

рдЕрд░реНрдерд╛рддреН, рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рддрд╛рд▓рд┐рдХрд╛ рдкрдВрдХреНрддрд┐ рдХреА рд╕рдВрдкреВрд░реНрдг рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдЕрднрд┐рд▓реЗрдЦреЛрдВ рдХреА рд╕реАрдЯреАрдЖрдИрдбреА тАЛтАЛрдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рд╡рд┐рдХрд▓реНрдк рдкреВрд░реА рдкрдВрдХреНрддрд┐ рдХреЛ рдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдбрд╛рд▓рдирд╛ рд╣реИ:

SELECT
  T::text
, array_agg(ctid) ctids
FROM
  tbl T
GROUP BY
  1;

t     | ctids
---------------------------------
(e,5) | {"(0,9)"}
(d,4) | {"(0,8)"}
(c,3) | {"(0,5)","(0,6)","(0,7)"}
(b,2) | {"(0,3)","(0,4)"}
(a,3) | {"(0,2)"}
(a,1) | {"(0,1)"}

рдХреНрдпрд╛ рдХрд╛рд╕реНрдЯ рди рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ?рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдЕрдзрд┐рдХрд╛рдВрд╢ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдпрд╣ рд╕рдВрднрд╡ рд╣реИред рдЬрдм рддрдХ рдЖрдк рдЗрд╕ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдлрд╝реАрд▓реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд░рддреЗ рд╕рдорд╛рдирддрд╛ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдмрд┐рдирд╛ рдкреНрд░рдХрд╛рд░:

CREATE TABLE tbl(k text, v integer, x point);
SELECT
  array_agg(ctid) ctids
FROM
  tbl T
GROUP BY
  T;
-- ERROR:  could not identify an equality operator for type tbl

рд╣рд╛рдБ, рд╣рдо рддреБрд░рдВрдд рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдпрджрд┐ рд╕рд░рдгреА рдореЗрдВ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпрд╛рдБ рд╣реИрдВ, рддреЛ рдпреЗ рд╕рднреА рдХреНрд▓реЛрди рд╣реИрдВред рдЖрдЗрдП рдЙрдиреНрд╣реЗрдВ рдЫреЛрдбрд╝ рджреЗрдВ:

SELECT
  unnest(ctids[2:])
FROM
  (
    SELECT
      array_agg(ctid) ctids
    FROM
      tbl T
    GROUP BY
      T::text
  ) T;

unnest
------
(0,6)
(0,7)
(0,4)

рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЫреЛрдЯрд╛ рд▓рд┐рдЦрдирд╛ рдкрд╕рдВрдж рдХрд░рддреЗ рд╣реИрдВрдЖрдк рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рднреА рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ:

SELECT
  unnest((array_agg(ctid))[2:])
FROM
  tbl T
GROUP BY
  T::text;

рдЪреВрдВрдХрд┐ рдХреНрд░рдордмрджреНрдз рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд╛ рдорд╛рди рд╕реНрд╡рдпрдВ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдк рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдордиреЗ рдЗрд╕реЗ рд╕рдмрдХреНрд╡реЗрд░реА рдХреЗ рд▓реМрдЯрд╛рдП рдЧрдП рдХреЙрд▓рдо рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд╛рд▓ рджрд┐рдпрд╛ред

рдмрд╕ рдереЛрдбрд╝рд╛ рд╕рд╛ рдХрд╛рдо рдмрд╛рдХреА рд╣реИ - DELETE рдХреЛ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╛рдкреНрдд рд╕реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:

DELETE FROM
  tbl
WHERE
  ctid = ANY(ARRAY(
    SELECT
      unnest(ctids[2:])
    FROM
      (
        SELECT
          array_agg(ctid) ctids
        FROM
          tbl T
        GROUP BY
          T::text
      ) T
  )::tid[]);

рдЖрдЗрдП рд╕реНрд╡рдпрдВ рдЬрд╛рдБрдЪреЗрдВ:

рдкреАрдХреЗ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░рдирд╛
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

рд╣рд╛рдВ, рд╕рдм рдХреБрдЫ рд╕рд╣реА рд╣реИ: рд╣рдорд╛рд░реЗ 3 рд░рд┐рдХреЙрд░реНрдб рд╕рдВрдкреВрд░реНрдг рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рдПрдХрдорд╛рддреНрд░ Seq рд╕реНрдХреИрди рдХреЗ рд▓рд┐рдП рдЪреБрдиреЗ рдЧрдП рдереЗ, рдФрд░ рдбреЗрдЯрд╛ рдХреА рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдбрд┐рд▓реАрдЯ рдиреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдЯрд┐рдб рд╕реНрдХреИрди рдХреЗ рд╕рд╛рде рд╕рд┐рдВрдЧрд▓ рдкрд╛рд╕:

->  Tid Scan on tbl (actual time=0.050..0.051 rows=3 loops=1)
      TID Cond: (ctid = ANY ($0))

рдпрджрд┐ рдЖрдкрдиреЗ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░ рджрд┐рдП рд╣реИрдВ, VACUUM ANALYZE рдЪрд▓рд╛рдирд╛ рди рднреВрд▓реЗрдВ.

рдЖрдЗрдП рдПрдХ рдмрдбрд╝реА рддрд╛рд▓рд┐рдХрд╛ рдФрд░ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

TRUNCATE TABLE tbl;

INSERT INTO tbl
SELECT
  chr(ascii('a'::text) + (random() * 26)::integer) k -- a..z
, (random() * 100)::integer v -- 0..99
FROM
  generate_series(1, 10000) i;

рдкреАрдХреЗ рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рдХреНрд▓реЛрди рд░рд┐рдХреЙрд░реНрдб рд╕рд╛рдлрд╝ рдХрд░рдирд╛
[рджреЗрдЦреЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛.рдЯреЗрдВрд╕рд░.рдЖрд░рдпреВ]

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

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

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