sql >> Databasteknik >  >> RDS >> PostgreSQL

Duplicera rader i en primärnyckeltabell.

Tillbaka igen, får mycket mindre tid att blogga 🙂

"FEL:kunde inte skapa ett unikt index
DETALJ:Tabellen innehåller dubblerade värden."

Det här felet kastas ut av Postgres när det stöter på dubbletter av rader i en primärnyckeltabell genom att misslyckas med något av dessa kommandon REINDEX eller CREATE UNIQUE INDEX.

Varför finns det dubbletter av rader i en tabell?

Inte säker exakt 🙂 eller några bevisade förklaringar...
Två saker tycker jag.

För det första kan det vara försenat att skapa index eller om du har delat sekvenser i en databas, kan delning på två olika primära nyckeltabeller vara orsaken när du återställer data till tabellen (pg_restore). För det andra, om någon stor transaktion äger rum på det bordet och i backend-enheten har någon abrupt stoppat instansen, vilket också kan misslyckas med att indexet (primärnyckeln) pekar på den högra raden.

Hur fixar jag det?

Tja, som vanligt, när vi stöter på en dubblettrad i en tabell (trots av någon anledning), filtrerar vi först dubblettraderna och tar bort dem, och senare bör REINDEX åtgärda problemet.

Fråga för att hitta dubbletter av rader:

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

Även efter att raderingen av dubblettraderna REINDEX eller CREATE UNIQUE INDEX misslyckas betyder det att ditt index inte rensas ordentligt. Ovanstående fråga kanske inte ger 100 % resultatorienterad utdata vad du förväntar dig, eftersom frågan kommer att välja indexet som redan är skadat med dubbletter av rader. Se förklaringsplanen nedan.

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 måste fånga CTID för dubbletter av rader från huvudtabellen och ta bort med villkorlig sats som CTID + PRIMÄRT NYCKELVÄRDE.

Jag har lekt lite med pg_catalogs för att voilate Primary Key Table för att återskapa scenariot med liknande fel. (Snälla gör det inte)

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

Min tabelldefinition och 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)

Nu, låt oss fixa detta...

Steg 1. Skapa en ny tabell från påverkad tabell genom att bara dra två kolumnvärden CTID och PRIMARY KEY.

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

Steg 2. Låt oss nu köra dubblettsökaren med CTID för att få exakta dubbletter.

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)

Steg 3. På resultatet ovan kan du nu ta bort en rad från huvudtabellen (påverkad tabell) med CTID.

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

Steg 4. Nu kommer din REINDEX eller CREATE UNIQUE INDEX att lyckas.

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)

Steg 5. Glöm inte att göra omedelbar VAKUUMANALYS på bordet för att uppdatera systemkatalogerna samt CTID-rörelser.

Dela gärna dina kommentarer.


  1. Intel SSD, nu utanför sh..err, skamlistan

  2. Skriver ut värdet på en variabel i SQL Developer

  3. SQLAlchemy func.count på boolesk kolumn

  4. Få toppresultat för varje grupp (i Oracle)