PK නොමැති වගුවකින් ක්ලෝන වාර්තා හිස් කිරීම

විට තත්වයන් තිබේ ප්‍රාථමික යතුරක් නැති මේසයකට හෝ වෙනත් සුවිශේෂී දර්ශකයක්, අධීක්‍ෂණයක් හේතුවෙන්, දැනටමත් පවතින වාර්තාවල සම්පූර්ණ ක්ලෝන ඇතුළත් වේ.

PK නොමැති වගුවකින් ක්ලෝන වාර්තා හිස් කිරීම

උදාහරණයක් ලෙස, කාලානුක්‍රමික මෙට්‍රික් එකක අගයන් පිටපත් ප්‍රවාහයක් භාවිතයෙන් PostgreSQL වෙත ලියා ඇත, පසුව හදිසි අසාර්ථකත්වයක් ඇති අතර සම්පූර්ණයෙන්ම සමාන දත්ත වලින් කොටසක් නැවත පැමිණේ.

අනවශ්‍ය ක්ලෝන වල දත්ත සමුදාය ඉවත් කරන්නේ කෙසේද?

PK උදව්කරුවෙකු නොවන විට

පහසුම ක්‍රමය නම් එවැනි තත්ත්වයක් ඇති වීම වැළැක්වීමයි. උදාහරණයක් ලෙස, ප්‍රාථමික යතුර රෝල් කරන්න. නමුත් ගබඩා කර ඇති දත්ත පරිමාව වැඩි නොකර මෙය සැමවිටම කළ නොහැක.

උදාහරණයක් ලෙස, මූලාශ්‍ර පද්ධතියේ නිරවද්‍යතාවය දත්ත සමුදායේ ඇති ක්ෂේත්‍රයේ නිරවද්‍යතාවයට වඩා වැඩි නම්:

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 වෙනුවට ගණන් කිරීම තත්පරයකට පෙර ts සමඟ දත්ත ගබඩාවේ සටහන් විය, නමුත් යෙදුම් දෘෂ්ටි කෝණයෙන් තරමක් වලංගු විය (සියල්ලට පසු, දත්ත අගයන් වෙනස් වේ!).

ඇත්ත වශයෙන්ම ඔබට එය කළ හැකිය PK(මිතික, ts) - නමුත් එවිට අපට වලංගු දත්ත සඳහා ඇතුළත් කිරීමේ ගැටුම් ලැබෙනු ඇත.

කරන්න පුළුවන් PK(මිතික, ts, දත්ත) - නමුත් මෙය එහි පරිමාව බෙහෙවින් වැඩි කරනු ඇත, එය අප භාවිතා නොකරනු ඇත.

එමනිසා, වඩාත් නිවැරදි විකල්පය වන්නේ නිතිපතා අද්විතීය නොවන දර්ශකයක් සෑදීමයි (මෙට්රික්, ටීඑස්) ප්‍රශ්න ඇති වූ පසු ඒවා සමඟ කටයුතු කරන්න.

"ක්ලෝනික් යුද්ධය ආරම්භ වී ඇත"

යම් ආකාරයක අනතුරක් සිදු වූ අතර, දැන් අපට මේසයෙන් ක්ලෝන වාර්තා විනාශ කළ යුතුය.

PK නොමැති වගුවකින් ක්ලෝන වාර්තා හිස් කිරීම

අපි මුල් දත්ත ආකෘති කරමු:

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 හිරවෙලා, දැන්...

පළමුව, අපගේ මේසය ඉතා විශාල විය හැකි බව අපි තේරුම් ගනිමු, එබැවින් අපි සියලු ක්ලෝන සොයා ගත් පසු, මකා දැමීමට වචනාර්ථයෙන් “අපේ ඇඟිල්ල දිගු කිරීම” සුදුසුය. නිශ්චිත වාර්තා නැවත සෙවීමකින් තොරව.

එවැනි ක්රමයක් තිබේ - මෙය ctid මගින් ඇමතීම, නිශ්චිත වාර්තාවක භෞතික හඳුනාගැනීම.

එනම්, පළමුවෙන්ම, අපි වගු පේළියේ සම්පූර්ණ අන්තර්ගතයේ සන්දර්භය තුළ වාර්තාවල ctid එකතු කළ යුතුය. සරලම විකල්පය වන්නේ සම්පූර්ණ පේළිය පෙළට දැමීමයි:

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[]);

අපි අපවම පරීක්ෂා කර බලමු:

PK නොමැති වගුවකින් ක්ලෝන වාර්තා හිස් කිරීම
[විස්තර කරන්න.tensor.ru බලන්න]

ඔව්, සියල්ල නිවැරදියි: අපගේ වාර්තා 3 සම්පූර්ණ වගුවේ එකම Seq ස්කෑන් සඳහා තෝරාගෙන ඇති අතර දත්ත සෙවීමට මකන්න නෝඩය භාවිතා කරන ලදී. Tid Scan සමඟ තනි සාමාර්ථය:

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

PK නොමැති වගුවකින් ක්ලෝන වාර්තා හිස් කිරීම
[විස්තර කරන්න.tensor.ru බලන්න]

එබැවින්, ක්රමය සාර්ථකව ක්රියාත්මක වේ, නමුත් එය යම් ප්රවේශම් සහිතව භාවිතා කළ යුතුය. මක්නිසාද යත් මකා දමන සෑම වාර්තාවකටම, Tid Scan හි කියවන එක් දත්ත පිටුවක් සහ Delete හි එකක් ඇත.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න