PK کان سواءِ ٽيبل تان ڪلون رڪارڊ صاف ڪرڻ

حالتون آهن جڏهن بنيادي چاٻي جي بغير ٽيبل تي يا ڪجهه ٻيو منفرد انڊيڪس، هڪ نگراني جي ڪري، اڳ ۾ موجود رڪارڊ جا مڪمل ڪلون شامل آهن.

PK کان سواءِ ٽيبل تان ڪلون رڪارڊ صاف ڪرڻ

مثال طور، هڪ تاريخ جي ميٽرڪ جا قدر هڪ ڪاپي اسٽريم استعمال ڪندي PostgreSQL ۾ لکيل آهن، ۽ پوءِ اوچتو ناڪامي آهي، ۽ مڪمل طور تي هڪجهڙائي واري ڊيٽا جو حصو ٻيهر اچي ٿو.

غير ضروري کلون جي ڊيٽابيس کي ڪيئن ختم ڪجي؟

جڏهن ته پ پ جو مددگار ناهي

سڀ کان آسان طريقو اهو آهي ته اهڙي صورتحال کي پهرين جڳهه ۾ ٿيڻ کان روڪڻ. مثال طور، رول PRIMARY KEY. پر اهو هميشه ممڪن ناهي ته ذخيرو ٿيل ڊيٽا جي مقدار کي وڌائڻ کان سواء.

مثال طور، جيڪڏهن ماخذ سسٽم جي درستگي ڊيٽابيس ۾ فيلڊ جي درستگي کان وڌيڪ آهي:

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 (ميٽرڪ، ٽي، ڊيٽا) - پر اهو ان جي مقدار کي تمام گهڻو وڌائيندو، جيڪو اسان استعمال نه ڪنداسين.

تنهن ڪري، سڀ کان وڌيڪ صحيح اختيار هڪ باقاعده غير منفرد انڊيڪس ٺاهڻ آهي (ميٽرڪ، ٽي ايس) ۽ حقيقت کان پوءِ مسئلا حل ڪريو جيڪڏهن اهي پيدا ٿين.

"ڪلونڪ جنگ شروع ٿي چڪي آهي"

ڪجهه قسم جو حادثو ٿيو، ۽ هاڻي اسان کي ميز تان ڪلون رڪارڊ کي تباهه ڪرڻو پوندو.

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 کان سواءِ ٽيبل تان ڪلون رڪارڊ صاف ڪرڻ
[explanation.tensor.ru تي ڏسو]

ها، سڀ ڪجهه صحيح آهي: اسان جا 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;

PK کان سواءِ ٽيبل تان ڪلون رڪارڊ صاف ڪرڻ
[explanation.tensor.ru تي ڏسو]

تنهن ڪري، طريقو ڪاميابي سان ڪم ڪري ٿو، پر اهو ڪجهه احتياط سان استعمال ڪيو وڃي. ڇو ته ڊليٽ ٿيل هر رڪارڊ لاءِ، ٽيڊ اسڪين ۾ هڪ ڊيٽا جو صفحو پڙهيو ويندو آهي، ۽ هڪ حذف ۾.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو