"CHYBA:nelze vytvořit jedinečný index
DETAIL:Tabulka obsahuje duplicitní hodnoty."
Tuto chybu Postgres vyhodí, když narazí na duplicitní řádky v tabulce primárních klíčů selháním některého z těchto příkazů REINDEX nebo CREATE UNIQUE INDEX.
Proč v tabulce existují duplicitní řádky?
Nejsem si jistý přesně 🙂 ani žádné ověřené vysvětlení...
Napadají mě dvě věci.
Za prvé to může být zpožděné vytvoření indexu nebo pokud máte sdílené sekvence v databázi, může být příčinou sdílení na dvou různých tabulkách primárního klíče při obnově dat do tabulky (pg_restore). Za druhé, pokud na tomto stole probíhá nějaká velká transakce a na backendu někdo náhle zastavil instanci, což by také mohlo selhat, aby index (primární klíč) ukazoval na správný řádek.
Jak to opravit?
Jak je běžnou praxí, když narazíme na duplicitní řádky v tabulce (bez ohledu na důvod), nejprve duplicitní řádky odfiltrujeme a odstraníme, a později by měl problém vyřešit REINDEX.
Dotaz na hledání duplicitních řádků:
select count(*),primary_column from table_name group by primary_column having count(*) > 1;
I po odstranění duplicitních řádků REINDEX nebo CREATE UNIQUE INDEX selže, znamená to, že váš index není správně vyčištěn. Výše uvedený dotaz nemusí poskytovat 100% výstup orientovaný na výsledek to, co očekáváte, protože dotaz vybere index, který je již poškozen duplicitními řádky. Viz plán vysvětlení níže.
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)
Potřebujeme zachytit CTID duplicitních řádků z hlavní tabulky a odstranit podmíněným příkazem jako CTID + HODNOTA PRIMÁRNÍHO KLÍČE.
Trochu jsem si pohrál s pg_catalogs, abych porušil tabulku primárních klíčů, abych reprodukoval scénář s podobnou chybou. (Prosím, nedělejte to)
postgres=# create unique index idup on duplicate_test(id);
ERROR: could not create unique index "idup"
DETAIL: Key (id)=(10) is duplicated.
Definice a data mé tabulky:
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)
Teď to napravíme…
Krok 1 Vytvořte novou tabulku z ovlivněné tabulky vytažením pouze dvou hodnot sloupců CTID a PRIMARY KEY.
postgres=# CREATE TABLE dupfinder AS SELECT ctid AS tid, id FROM duplicate_test;
SELECT 4
Krok 2 Nyní spusťte dotaz na vyhledávání duplicit s CTID, abyste získali přesné duplikáty.
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)
Krok 3 Na výše uvedeném výsledku nyní můžete odstranit jeden řádek z hlavní tabulky (efektované tabulky) s CTID.
postgres=# delete from duplicate_test where ctid='(0,5)' and id=10;
DELETE 1
Krok 4 Nyní bude váš REINDEX nebo CREATE UNIQUE INDEX úspěšný.
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)
Krok 5 Nezapomeňte okamžitě provést VACUUM ANALYZE na stole, abyste aktualizovali systémové katalogy a také pohyb CTID.
Prosím, podělte se o své komentáře.