„ГРЕШКА:не можа да се създаде уникален индекс
ПОДРОБНО:Таблицата съдържа дублирани стойности.“
Тази грешка се изхвърля от Postgres, когато срещне дублиращи се редове в таблицата с първичен ключ, като не успее някоя от тези команди REINDEX или CREATE UNIQUE INDEX.
Защо в таблица съществуват дублиращи се редове?
Не съм сигурен точно 🙂 нито някакви доказани обяснения...
Според мен има две неща.
Първо, може да е забавено създаване на индекс или ако имате споделени последователности в база данни, споделянето на две различни таблици с първичен ключ може да е причината при възстановяване на данните в таблица (pg_restore). Второ, ако на тази таблица се извършва някаква огромна транзакция и в бекенда някой внезапно е спрял екземпляра, което също може да провали индекса (първичния ключ) да сочи към десния ред.
Как да го поправя?
Е, като обичайна практика, когато срещнем дублиращи се редове в таблица (въпреки някаква причина), първо филтрираме дублиращите се редове и ги изтриваме, а по-късно чрез REINDEX трябва да решим проблема.
Заявка за намиране на дублиращи се редове:
изберете count(*),primary_column от групата table_name по primary_column с брой (*)> 1;
Дори след неуспешно изтриване на дублиращи се редове REINDEX или CREATE UNIQUE INDEX, това означава, че вашият индекс не е почистен правилно. Горната заявка може да не дава 100% ориентиран към резултатите изход, който очаквате, защото заявката ще избере индекса, който вече е повреден с дублиращи се редове. Вижте плана за обяснение по-долу.
postgres=# обяснете изберете count(*), идентификатор от групата duplicate_test по идентификатор с count(*)> 1;
ПЛАН НА ЗАЯВКАТА
------------ -------------------------------------------------- ----------------------------------------
GroupAggregate (цена=0,00. .5042,90 реда=99904 ширина=4)
Филтър:(брой(*)> 1)
-> Индексно сканиране с помощта на duplicate_test_pkey на duplicate_test (цена=0,00..3044,82 реда=99904 ширина=4)
(3 реда)
Трябва да хванем CTID на дублиращи се редове от основната таблица и да изтрием с условен израз като CTID + ПЪРВИЧЕН КЛЮЧ СТОЙНОСТ.
Поиграх малко с pg_catalogs, за да проваля таблицата с първичен ключ, за да възпроизведем сценария с подобна грешка. (Моля, не го правете)
postgres=# създаване на уникален индекс idup на duplicate_test(id);
ГРЕШКА:не можа да се създаде уникален индекс "idup"
ПОДРОБНОСТИ:Ключ (id)=(10) е дублиран.
пред>Дефиниция и данни на моята таблица:
postgres=# d duplicate_test
Таблица "public.duplicate_test"
Колона | Тип | Модификатори
-------+-------+----------
id | цяло число | не null
име | текст |
Индекси:
"duplicate_test_pkey" ПЪРВИЧЕН КЛЮЧ, btree (id)
postgres=# изберете * от duplicate_test;
id | име
----+--------
10 | Raghav ---Дублиране
20 | Джон H
30 | Майкъл
10 | Raghav ---Дублиране
(4 реда)Сега нека поправим това...
Стъпка 1. Създайте нова таблица от извършената таблица, като изтеглите само две стойности на колони CTID и PRIMARY KEY.
postgres=# СЪЗДАЙТЕ ТАБЛИЦА dupfinder КАТО ИЗБЕРЕТЕ ctid КАТО tid, id ОТ duplicate_test;
ИЗБЕРЕТЕ 4Стъпка 2. Сега нека стартираме заявката за намиране на дубликати с CTID, за да получим точните дубликати.
postgres=# изберете * от dupfinder x, където съществува (изберете 1 от dupfinder y, където x.id =y.id и x.tid !=y.tid);
tid | id
-------+----
(0,1) | 10
(0,5) | 10
(2 реда)Стъпка 3. В резултата по-горе сега можете да изтриете един ред от основната таблица (ефектната таблица) с CTID.
postgres=# изтриване от duplicate_test, където ctid='(0,5)' и id=10;
ИЗТРИВАНЕ 1Стъпка 4. Сега вашият REINDEX или CREATE UNIQUE INDEX ще бъде успешен.
postgres=# създаване на уникален индекс idup на duplicate_test(id);
СЪЗДАВАНЕ НА ИНДЕКС
postgres=# изберете * от duplicate_test;
id | име
----+--------
10 | Рагхав
20 | Джон H
30 | Майкъл
(3 реда)Стъпка 5. Не забравяйте да направите незабавен ВАКУУМЕН АНАЛИЗ на масата, за да актуализирате системните каталози, както и движението на CTID.
Моля, споделете вашите коментари.