PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Doppelte Zeilen in einer Primärschlüsseltabelle.

Wieder zurück, habe sehr weniger Zeit zum Bloggen 🙂

„FEHLER:Eindeutiger Index konnte nicht erstellt werden
DETAIL:Tabelle enthält doppelte Werte.“

Dieser Fehler wird von Postgres ausgegeben, wenn es auf doppelte Zeilen in einer Primärschlüsseltabelle trifft, indem einer dieser Befehle REINDEX oder CREATE UNIQUE INDEX fehlschlägt.

Warum gibt es doppelte Zeilen in einer Tabelle?

Ich bin mir nicht ganz sicher 🙂 und es gibt auch keine bewiesenen Erklärungen…
Zwei Dinge, die mir einfallen.

Erstens kann es sich um eine verzögerte Indexerstellung handeln, oder wenn Sie Sequenzen in einer Datenbank gemeinsam genutzt haben, kann die gemeinsame Nutzung in zwei verschiedenen Primärschlüsseltabellen die Ursache sein, während die Daten in der Tabelle (pg_restore) wiederhergestellt werden. Zweitens, wenn eine große Transaktion auf dieser Tabelle stattfindet und jemand am Backend die Instanz abrupt gestoppt hat, kann es auch passieren, dass der Index (Primärschlüssel) nicht auf die richtige Zeile zeigt.

Wie kann ich es beheben?

Nun, als übliche Praxis, wenn wir auf doppelte Zeilen in einer Tabelle stoßen (egal aus welchem ​​Grund), filtern wir zuerst die doppelten Zeilen und löschen sie, und später sollte das Problem durch REINDEX behoben werden.

Abfrage zum Finden doppelter Zeilen:

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

Auch nachdem das Löschen der doppelten Zeilen REINDEX oder CREATE UNIQUE INDEX fehlschlägt, bedeutet dies, dass Ihr Index nicht ordnungsgemäß bereinigt wird. Die obige Abfrage liefert möglicherweise nicht die von Ihnen erwartete 100% ergebnisorientierte Ausgabe, da die Abfrage den Index auswählen wird, der bereits mit doppelten Zeilen beschädigt ist. Siehe Erklärungsplan unten.

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)

Wir müssen die CTID doppelter Zeilen aus der Haupttabelle abfangen und mit einer bedingten Anweisung als CTID + PRIMARY KEY VALUE löschen.

Ich habe ein bisschen mit pg_catalogs gespielt, um die Primärschlüsseltabelle zu voilieren, um das Szenario mit ähnlichem Fehler zu reproduzieren. (Bitte nicht)

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

Meine Tabellendefinition und -daten:

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)

Lassen Sie uns das jetzt beheben ….

Schritt 1. Erstellen Sie eine neue Tabelle aus der betroffenen Tabelle, indem Sie nur zwei Spaltenwerte CTID und PRIMARY KEY abrufen.

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

Schritt 2. Lassen Sie uns nun die Duplikatsuchabfrage mit CTID ausführen, um die genauen Duplikate zu erhalten.

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)

Schritt 3. Im obigen Ergebnis können Sie jetzt eine Zeile aus der Haupttabelle (betroffene Tabelle) mit CTID löschen.

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

Schritt 4. Jetzt wird Ihr REINDEX oder CREATE UNIQUE INDEX erfolgreich sein.

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)

Schritt 5. Vergessen Sie nicht, sofort eine VAKUUMANALYSE auf dem Tisch durchzuführen, um die Systemkataloge sowie die CTID-Bewegung zu aktualisieren.

Bitte teilen Sie Ihre Kommentare.