Ngabersihan rékaman clone tina méja tanpa PK

Aya kaayaan nalika kana méja tanpa konci primér atawa sababaraha indéks unik séjén, alatan hiji pangawasan, clones lengkep rékaman geus aya kaasup.

Ngabersihan rékaman clone tina méja tanpa PK

Salaku conto, nilai métrik kronologis ditulis kana PostgreSQL nganggo aliran COPY, teras aya kagagalan ngadadak, sareng bagian tina data anu sami sami sumping deui.

Kumaha carana miceun database tina clones teu perlu?

Kapan PK lain pembantu

Cara panggampangna nyaéta pikeun nyegah kaayaan sapertos kitu di tempat munggaran. Contona, gulung konci primér. Tapi ieu teu salawasna mungkin tanpa ngaronjatna volume data disimpen.

Salaku conto, upami akurasi sistem sumber langkung luhur tibatan akurasi lapangan dina pangkalan data:

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}

Naha anjeun perhatikeun? The countdown instead of 00:00:02 kacatet dina database kalawan ts sadetik saméméhna, tapi tetep cukup valid ti sudut pandang aplikasi (sanggeus kabeh, nilai data béda!).

Tangtu anjeun bisa ngalakukeun eta PK(métrik, ts) - tapi lajeng urang bakal meunang bentrok sisipan pikeun data valid.

Bisa ngalakukeun PK(métrik, ts, data) - tapi ieu bakal greatly ngaronjatkeun volume na, nu urang moal make.

Ku alatan éta, pilihan paling bener nyaéta nyieun indéks non-unik biasa (métrik, ts) sareng nungkulan masalah saatos kanyataan upami éta timbul.

"Perang klonik parantos dimimitian"

Sababaraha jenis kacilakaan kajantenan, sareng ayeuna urang kedah ngancurkeun rékaman clone tina méja.

Ngabersihan rékaman clone tina méja tanpa PK

Hayu urang model data aslina:

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

Di dieu leungeun urang ngageter tilu kali, Ctrl+V macét, ayeuna...

Mimiti, hayu urang ngartos yén méja urang tiasa ageung pisan, janten saatos urang mendakan sadaya klon, disarankeun pikeun sacara harfiah "nyodok ramo" pikeun ngahapus. rékaman husus tanpa ulang pilarian aranjeunna.

Sareng aya cara sapertos kitu - ieu alamat ku ctid, identifier fisik rékaman husus.

Hartina, mimiti sagala, urang kudu ngumpulkeun ctid tina rékaman dina konteks eusi lengkep baris tabel. Pilihan pangbasajanna nyaéta tuang sakabéh garis kana téks:

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)"}

Naha mungkin henteu tuang?Sacara prinsip, éta mungkin dina kalolobaan kasus. Nepi ka anjeun mimiti ngagunakeun widang dina tabel ieu jenis tanpa operator sarua:

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

Leres, urang langsung ningali yén upami aya langkung ti hiji éntri dina array, ieu sadayana klon. Hayu urang tinggalkeun aranjeunna:

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)

Pikeun anu resep nyerat langkung pondokAnjeun ogé tiasa nyerat sapertos kieu:

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

Kusabab nilai tina senar serialized sorangan teu metot pikeun urang, urang saukur threw eta kaluar tina kolom balik subquery nu.

Aya sakedik deui anu kedah dilakukeun - ngadamel DELETE nganggo set anu kami tampi:

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

Hayu urang pariksa diri:

Ngabersihan rékaman clone tina méja tanpa PK
[tingali dina explain.tensor.ru]

Leres, sadayana leres: 3 rékaman kami dipilih pikeun hiji-hijina Seq Scan tina sadaya méja, sareng titik Hapus dianggo pikeun milarian data. single pass kalawan Tid Scan:

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

Upami anjeun ngabersihan seueur rékaman, tong hilap ngajalankeun VACUUM ANALYZE.

Hayu urang parios tabel anu langkung ageung sareng jumlah duplikat anu langkung ageung:

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;

Ngabersihan rékaman clone tina méja tanpa PK
[tingali dina explain.tensor.ru]

Janten, metodeu tiasa suksés, tapi kedah dianggo kalayan ati-ati. Kusabab pikeun unggal catetan anu dihapus, aya hiji halaman data anu dibaca dina Tid Scan, sareng hiji di Hapus.

sumber: www.habr.com

Tambahkeun komentar