sql >> Database teknologi >  >> RDS >> PostgreSQL

Dupliker rækker i en primær nøgletabel.

Tilbage igen, får meget mindre tid til at blogge 🙂

"FEJL:kunne ikke oprette entydigt indeks
DETALJER:Tabellen indeholder duplikerede værdier."

Denne fejl bliver smidt ud af Postgres, når den støder på duplikerede rækker i en primær nøgletabel ved at mislykkes med en af ​​disse kommandoer REINDEX eller CREATE UNIQUE INDEX.

Hvorfor findes der dublerede rækker i en tabel?

Jeg er ikke helt sikker 🙂 eller nogen dokumenterede forklaringer...
Jeg tænker på to ting.

For det første kan det være forsinket indeksoprettelse, eller hvis du har delt sekvenser i en database, kan deling på to forskellige primærnøgletabeller være årsagen, mens dataene gendannes i tabellen (pg_restore). For det andet, hvis der finder en stor transaktion sted på det bord, og i backend nogen har brat stoppet forekomsten, hvilket også kan undlade at indekset (primær nøgle) peger på den højre række.

Hvordan rettes det?

Tja, som almindelig praksis, når vi støder på en dublet række i en tabel (på trods af en hvilken som helst årsag), filtrerer vi først de duplikerede rækker og sletter dem, og senere ved at gøre REINDEX skulle problemet løses.

Forespørgsel til at finde dublerede rækker:

select count(*),primary_column from table_name group by primary_column having count(*) > 1;

Selv efter sletning af de duplikerede rækker REINDEX eller CREATE UNIQUE INDEX mislykkes, betyder det, at dit indeks ikke er renset korrekt. Ovenstående forespørgsel giver muligvis ikke 100 % resultatorienteret output, hvad du forventer, fordi forespørgslen vil vælge det indeks, som allerede er beskadiget med duplikerede rækker. Se forklaringsplanen nedenfor.

postgres=# explain select count(*),id from duplicate_test group by id having count(*) > 1;
QUERY PLAN
-------------------------------------------------------------------------------------------------------
GroupAggregate (cost=0.00..5042.90 rows=99904 width=4)
Filter: (count(*) > 1)
-> Index Scan using duplicate_test_pkey on duplicate_test (cost=0.00..3044.82 rows=99904 width=4)
(3 rows)

Vi skal fange CTID af duplikerede rækker fra hovedtabellen og slette med betinget sætning som CTID + PRIMÆR NØGLEVÆRDI.

Jeg har leget lidt med pg_catalogs for at voilate Primary Key Table for at gengive scenariet med lignende fejl. (Gør det ikke)

postgres=# create unique index idup on duplicate_test(id);
ERROR: could not create unique index "idup"
DETAIL: Key (id)=(10) is duplicated.

Min tabeldefinition og data:

postgres=# d duplicate_test
Table "public.duplicate_test"
Column | Type | Modifiers
--------+---------+-----------
id | integer | not null
name | text |
Indexes:
"duplicate_test_pkey" PRIMARY KEY, btree (id)

postgres=# select * from duplicate_test ;
id | name
----+---------
10 | Raghav ---Duplicate
20 | John H
30 | Micheal
10 | Raghav ---Duplicate
(4 rows)

Lad os nu ordne dette...

Trin 1. Opret en ny tabel fra den påvirkede tabel ved kun at trække to kolonneværdier CTID og PRIMARY KEY.

postgres=# CREATE TABLE dupfinder AS SELECT ctid AS tid, id FROM duplicate_test;
SELECT 4

Trin 2. Lad os nu køre duplikatfinderforespørgslen med CTID for at få de nøjagtige dubletter.

postgres=# select * from dupfinder x where exists (select 1 from dupfinder y where x.id = y.id and x.tid != y.tid);
tid | id
-------+----
(0,1) | 10
(0,5) | 10
(2 rows)

Trin 3. På ovenstående resultat kan du nu slette en række fra hovedtabel (påvirket tabel) med CTID.

postgres=# delete from duplicate_test where ctid='(0,5)' and id=10;
DELETE 1

Trin 4. Nu vil din REINDEX eller CREATE UNIQUE INDEX blive vellykket.

postgres=# create unique index idup on duplicate_test(id);
CREATE INDEX

postgres=# select * from duplicate_test ;
id | name
----+---------
10 | Raghav
20 | John H
30 | Micheal
(3 rows)

Trin 5. Glem ikke at lave øjeblikkelig VAKUUMANALYSE på bordet for at opdatere systemkatalogerne samt CTID-bevægelse.

Del venligst dine kommentarer.


  1. Android - Bedre tilgang til indlæsning af SD-KORT-billeder

  2. SQL-server-identitetskolonneværdier starter ved 0 i stedet for 1

  3. date_trunc 5 minutters interval i PostgreSQL

  4. Sådan kontrolleres konfigurationsindstillingerne for databasemail i SQL Server (T-SQL)