Paqijkirina tomarên klonê ji tabloyek bêyî PK

Dema ku rewş hene li ser maseyek bêyî mifteya bingehîn an jî navnîşek bêhempa ya din, ji ber çavdêriyek, klonên bêkêmasî yên tomarên berê hene tê de hene.

Paqijkirina tomarên klonê ji tabloyek bêyî PK

Mînakî, nirxên metrîkek kronolojîk li PostgreSQL bi karanîna tîrêjek COPY têne nivîsandin, û dûv re têkçûnek ji nişka ve çêdibe, û beşek ji daneyên bi tevahî wekhev dîsa digihîje.

Meriv çawa databasê ji klonên nehewce xilas dike?

Dema ku PK ne arîkar e

Rêya herî hêsan ew e ku pêşî li rewşek wiha were girtin. Mînakî, PRIMARY KEY lîstin. Lê ev her gav bêyî zêdekirina qebareya daneyên hilandî ne gengaz e.

Mînakî, heke rastbûna pergala çavkaniyê ji rastbûna zeviyê di databasê de bilindtir e:

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}

Te ferq kir? Di şûna 00:00:02 de jimartin di databasê de bi ts-yê saniyeyek berê hate tomar kirin, lê ji hêla serîlêdanê ve pir derbasdar ma (piştî, nirxên daneyê cûda ne!).

Bê guman hûn dikarin bikin PK (metric, ts) - lê wê hingê em ê ji bo daneyên derbasdar nakokiyên têxê bistînin.

Dikane PK (metric, ts, data) - lê ev ê hêjmara wê pir zêde bike, ku em ê bikar neynin.

Ji ber vê yekê, vebijarka herî rast ev e ku meriv navnîşek ne-yekserî ya birêkûpêk çêbike (metrîk, ts) û bi pirsgirêkan re piştî ku rastî derkevin holê jî mijûl bibin.

"Şerê klonîk dest pê kir"

Hin celeb qeza çêbû, û naha divê em tomarên klonê ji tabloyê hilweşînin.

Paqijkirina tomarên klonê ji tabloyek bêyî PK

Ka em daneyên orîjînal model bikin:

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

Li vir destê me sê caran lerizî, Ctrl+V asê ma û êdî...

Pêşîn, em fêhm bikin ku tabloya me dikare pir mezin be, ji ber vê yekê piştî ku em hemî klonan bibînin, ji me re tê pêşniyar kirin ku em bi rastî "tiliya xwe bixin" da ku jêbirin. tomarên taybetî bêyî ku ji nû ve li wan bigerin.

Û rêyek wusa heye - ev navnîşan bi ctid, Nasnameya fîzîkî ya tomarek taybetî.

Ango, berî her tiştî, pêdivî ye ku em ctid tomaran di çarçoveya naveroka tevahî ya rêza tabloyê de berhev bikin. Vebijarka herî hêsan ev e ku meriv tevahiya rêzê binivîsîne:

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

Ma gengaz e ku meriv neyê avêtin?Di prensîbê de, ew di pir rewşan de gengaz e. Heya ku hûn dest bi karanîna zeviyên vê tabloyê bikin cureyên bêyî operatorê wekheviyê:

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

Erê, em tavilê dibînin ku heke di rêzê de ji yekê zêdetir têketin hebe, ev hemî klon in. Ka em tenê wan bihêlin:

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)

Ji bo kesên ku dixwazin kurt binivîsinHûn jî dikarin bi vî rengî binivîsin:

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

Ji ber ku nirxa rêzika rêzkirî bixwe ji me re ne balkêş e, me ew bi tenê ji stûnên vegerî yên jêrpirsînê avêt.

Tiştek hindik maye ku bikin - bikin DELETE seta ku me standiye bikar bîne:

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

Ka em xwe kontrol bikin:

Paqijkirina tomarên klonê ji tabloyek bêyî PK
[li ser şirove.tensor.ru binêre]

Erê, her tişt rast e: 3 tomarên me ji bo yekane Seq Scan ya tevahiya tabloyê hatin hilbijartin, û girêka jêbirinê ji bo lêgerîna daneyan hate bikar anîn. derbasbûna yekane bi Tid Scan:

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

Ger we gelek tomar paqij kir, ji bîr nekin ku VACUUM ANALYZE bimeşînin.

Werin em ji bo tabloyek mezintir û bi jimareyek mezin a dubareyan kontrol bikin:

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;

Paqijkirina tomarên klonê ji tabloyek bêyî PK
[li ser şirove.tensor.ru binêre]

Ji ber vê yekê, rêbaz bi serfirazî dixebite, lê divê ew bi hin hişyariyê were bikar anîn. Ji ber ku ji bo her tomarek ku tê jêbirin, rûpelek daneyê di Tid Scan de tê xwendin, û yek jî di Delete de.

Source: www.habr.com

Add a comment