sql >> Databáze >  >> RDS >> PostgreSQL

Duplikovat řádky v tabulce primárního klíče.

Znovu, získáváme mnohem méně času na blogování 🙂

"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.


  1. Zkraťte (ne zaokrouhlujte) desetinná místa v SQL Server

  2. Jak funguje funkce WEIGHT_STRING() v MySQL

  3. CRS 11.2.0

  4. SQL trasování, událost 10046 v Oracle:trcsess, nástroj tkprof