"ERRORE:impossibile creare un indice univoco
DETTAGLIO:la tabella contiene valori duplicati."
Questo errore viene eliminato da Postgres quando incontra righe duplicate in una tabella di chiavi primarie fallendo uno di questi comandi REINDEX o CREATE UNIQUE INDEX.
Perché in una tabella esistono righe duplicate?
Non sono sicuro esattamente 🙂 né alcuna spiegazione provata fuori...
Due cose a mio avviso.
In primo luogo, potrebbe essere la creazione ritardata dell'indice o se hai condiviso sequenze in un database, la condivisione su due diverse tabelle di chiavi primarie potrebbe essere la causa durante il ripristino dei dati nella tabella (pg_restore). In secondo luogo, se su quel tavolo è in corso una transazione di grandi dimensioni e nel back-end qualcuno ha interrotto bruscamente l'istanza, il che potrebbe anche non riuscire a indicare la riga destra dell'indice (chiave primaria).
Come risolverlo?
Ebbene, come prassi comune, quando incontriamo righe duplicate in una tabella (a prescindere da qualsiasi motivo), prima filtriamo le righe duplicate e le eliminiamo, quindi, facendo REINDEX, dovremmo risolvere il problema.
Query per trovare righe duplicate:
select count(*),primary_column from table_name group by primary_column having count(*) > 1;
Anche dopo aver eliminato le righe duplicate REINDEX o CREATE UNIQUE INDEX non riesce, significa che l'indice non è stato pulito correttamente. La query precedente potrebbe non fornire un output orientato ai risultati al 100% ciò che ti aspetti, perché la query sceglierà l'indice che è già danneggiato con righe duplicate. Vedi il piano esplicativo di seguito.
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)
Dobbiamo catturare CTID di righe duplicate dalla tabella principale ed eliminare con un'istruzione condizionale come CTID + VALORE CHIAVE PRIMARIA.
Ho giocato un po' con pg_catalogs per annullare la tabella delle chiavi primarie per riprodurre lo scenario con un errore simile. (Per favore, non farlo)
postgres=# create unique index idup on duplicate_test(id);
ERROR: could not create unique index "idup"
DETAIL: Key (id)=(10) is duplicated.
Definizione e dati della mia tabella:
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)
Ora, risolviamo questo problema...
Passaggio 1. Crea una nuova tabella dalla tabella effettuata estraendo solo due valori di colonna CTID e PRIMARY KEY.
postgres=# CREATE TABLE dupfinder AS SELECT ctid AS tid, id FROM duplicate_test;
SELECT 4
Passaggio 2. Ora, eseguiamo la query di ricerca duplicati con CTID per ottenere i duplicati esatti.
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)
Passaggio 3. Sul risultato sopra, ora puoi eliminare una riga dalla tabella principale (tabella effettuata) con CTID.
postgres=# delete from duplicate_test where ctid='(0,5)' and id=10;
DELETE 1
Passaggio 4. Ora, il tuo REINDEX o CREATE UNIQUE INDEX avrà successo.
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)
Passaggio 5. Non dimenticare di eseguire immediatamente l'ANALISI DEL VUOTO sul tavolo per aggiornare i cataloghi del sistema e il movimento CTID.
Per favore condividi i tuoi commenti.