Hemm sitwazzjonijiet meta għal mejda mingħajr ċavetta primarja jew xi indiċi uniku ieħor, minħabba sorveljanza, kloni kompluti ta 'rekords diġà eżistenti huma inklużi.
Pereżempju, il-valuri ta 'metrika kronoloġika jinkitbu f'PostgreSQL bl-użu ta' COPY stream, u mbagħad ikun hemm falliment f'daqqa, u parti mid-dejta kompletament identika tasal mill-ġdid.
Kif teħles id-database minn kloni mhux meħtieġa?
Meta PK ma jkunx helper
L-eħfef mod huwa li tevita li sitwazzjoni bħal din isseħħ fl-ewwel lok. Per eżempju, roll PRIMARY KEY. Iżda dan mhux dejjem ikun possibbli mingħajr ma jiżdied il-volum tad-dejta maħżuna.
Pereżempju, jekk l-eżattezza tas-sistema tas-sors hija ogħla mill-eżattezza tal-qasam fid-database:
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}
Innutajt? Il-countdown minflok 00:00:02 ġie rreġistrat fid-database b'ts sekonda qabel, iżda baqa 'pjuttost validu mil-lat tal-applikazzjoni (wara kollox, il-valuri tad-dejta huma differenti!).
Naturalment tista 'tagħmel dan PK(metrika, ts) - iżda mbagħad se jkollna kunflitti ta 'inserzjoni għal data valida.
Tista 'tagħmel PK(metrika, ts, data) - iżda dan se jżid ħafna l-volum tiegħu, li aħna mhux se nużaw.
Għalhekk, l-iktar għażla korretta hija li tagħmel indiċi regolari mhux uniku (metrika, ts) u jittrattaw problemi wara l-fatt jekk jinqalgħu.
"Il-gwerra klonika bdiet"
Ġara xi tip ta 'inċident, u issa rridu neqirdu r-rekords tal-kloni mit-tabella.
Ejja nmudellaw id-dejta oriġinali:
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)
;
Hawnhekk idejna tregħddet tliet darbiet, Ctrl+V teħel, u issa...
L-ewwel, ejja nifhmu li t-tabella tagħna tista 'tkun kbira ħafna, għalhekk wara li nsibu l-kloni kollha, huwa rakkomandabbli għalina li litteralment "poke subgħajna" biex inħassru rekords speċifiċi mingħajr ma jerġgħu jfittxuhom.
U hemm mod bħal dan - dan
Jiġifieri, l-ewwel nett, għandna bżonn niġbru l-ctid tar-rekords fil-kuntest tal-kontenut sħiħ tar-ringiela tat-tabella. L-iktar għażla sempliċi hija li titfa' l-linja kollha fit-test:
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)"}
Huwa possibbli li ma titfax?Fil-prinċipju, huwa possibbli f'ħafna każijiet. Sakemm tibda tuża oqsma f'din it-tabella tipi mingħajr operatur ta' ugwaljanza:
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
Iva, naraw immedjatament li jekk ikun hemm aktar minn entrata waħda fil-firxa, dawn huma kollha kloni. Ejja nħalluhom:
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)
Għal dawk li jħobbu jikteb iqsarTista 'wkoll tikteb hekk:
SELECT
unnest((array_agg(ctid))[2:])
FROM
tbl T
GROUP BY
T::text;
Peress li l-valur tas-sekwenza serjali nnifisha mhuwiex interessanti għalina, aħna sempliċement thaddbuha mill-kolonni rritornati tas-subquery.
Fadal ftit xi jsir - agħmel li DELETE juża s-sett li rċevejna:
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[]);
Ejja niċċekkjaw lilna nfusna:
Iva, kollox huwa korrett: it-3 rekords tagħna ġew magħżula għall-unika Seq Scan tat-tabella kollha, u n-node Ħassar intuża biex tfittex dejta pass wieħed b'Tid Scan:
-> Tid Scan on tbl (actual time=0.050..0.051 rows=3 loops=1)
TID Cond: (ctid = ANY ($0))
Jekk kklerjat ħafna rekords,
Ejja niċċekkjaw għal tabella akbar u b'numru akbar ta 'duplikati:
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;
Għalhekk, il-metodu jaħdem b'suċċess, iżda għandu jintuża b'ċerta kawtela. Minħabba li għal kull rekord li jitħassar, hemm paġna tad-dejta waħda tinqara f'Tid Scan, u waħda f'Ħassar.
Sors: www.habr.com